Возможное менее совершенное решение моего собственного вопроса:
1. Не беспокойтесь о методах и используйте вместо этого отдельно стоящие функции.
struct CoreData
{
int m_x;
~CoreData();
};
void TeamA_init(CoreData& data);
void TeamA_push_back(CoreData& data, Whatever args);
Iter TeamA_begin(CoreData& data);
bool TeamB_init(CoreData& data, Other args);
bool TeamB_push_back(CoreData& data, Whatever args);
X* TeamB_begin(CoreData& data);
//--------------------- Usage:
void ServiceOfTeamA::CallServiceOfTeamB(ServiceOfTeamB* srv)
{
CoreData d;
TeamA_init(d);
srv->Process(&d);
TeamA_begin(d);
}
void ServiceOfTeamB::Process(CoreData* d)
{
TeamB_push_back(*d, 567);
}
- Что мне не нравится в этом подходе, так это недружественный синтаксис, никакой RAII и все члены данных не являются открытыми. Это C, а не C ++.
+ С другой стороны, этот подход предлагает неограниченные возможности настройки. Нет ограничений в выборе правильной функции для задачи. Никаких накладных расходов на память, никаких накладных расходов на выполнение (то есть, технически компилятор имеет те же возможности вставки и оптимизации, что и методы, которые эти свободные функции будут использовать).
По сути, после просмотра результатов Google я начал с информации из ветки обсуждения MSDN, где Dr. WPF предоставил ответ , в котором говорится о стилизации ListBox для просмотра. право. Однако, когда список отключен, фон был раздражающим цветом, от которого я не мог избавиться до конца жизни, пока не прочитал пример MSDN ListBox ControlTemplate , который показывает секретную границу элемент, который пинал мою заднюю часть фона.
Итак, окончательный ответ здесь был этот стиль:
<Style x:Key="RadioButtonList" TargetType="{x:Type ListBox}">
<!-- ControlTemplate taken from MSDN http://msdn.microsoft.com/en-us/library/ms754242.aspx -->
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="MinWidth" Value="120"/>
<Setter Property="MinHeight" Value="95"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<Border Name="Border" Background="Transparent"
BorderBrush="Transparent"
BorderThickness="0"
CornerRadius="2">
<ScrollViewer Margin="0" Focusable="false">
<StackPanel Margin="2" IsItemsHost="True" />
</ScrollViewer>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="Border" Property="Background"
Value="Transparent" />
<Setter TargetName="Border" Property="BorderBrush"
Value="Transparent" />
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type ListBoxItem}" >
<Setter Property="Margin" Value="2" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border Name="theBorder" Background="Transparent">
<RadioButton Focusable="False" IsHitTestVisible="False"
IsChecked="{TemplateBinding IsSelected}">
<ContentPresenter />
</RadioButton>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
, который предоставляет ControlTemplate и стили для ListBox и Items. И к этому привыкаешь вот так:
<ListBox Grid.Column="1" Grid.Row="0" x:Name="TurnChargeBasedOnSelector" Background="Transparent"
IsEnabled="{Binding Path=IsEditing}"
Style="{StaticResource RadioButtonList}"
ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:MainForm}}, Path=DataContext.RampTurnsBasedOnList}"
DisplayMemberPath="Description" SelectedValuePath="RampTurnsBasedOnID"
SelectedValue="{Binding Path=RampTurnsBasedOnID, NotifyOnValidationError=True, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}"/>
Чем больше я провожу время с WPF, тем больше я думаю, что это делает тривиальное безумно трудным и безумно сложным тривиальным. Наслаждаться. -Скотт
Я сделал это через ValueConverter
, который преобразует перечисление
в bool
. Передав значение перечисления, которое ваша радиокнопка представляет в виде ConverterParameter
, конвертер возвращает информацию о том, должна ли эта радиокнопка быть проверена или нет.
<Window.Resources>
<Converters:EnumConverter x:Key="EnumConverter" />
</Window.Resources>
<RadioButton IsChecked="{Binding Path=MyEnum, Mode=TwoWay,
Converter={StaticResource EnumConverter},
ConverterParameter=Enum1}"}
Content="Enum 1" />
<RadioButton IsChecked="{Binding Path=MyEnum, Mode=TwoWay,
Converter={StaticResource EnumConverter},
ConverterParameter=Enum2}"}
Content="Enum 2" />
EnumConverter
определяется следующим образом:
public class EnumConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (targetType.IsAssignableFrom(typeof(Boolean)) && targetType.IsAssignableFrom(typeof(String)))
throw new ArgumentException("EnumConverter can only convert to boolean or string.");
if (targetType == typeof(String))
return value.ToString();
return String.Compare(value.ToString(), (String)parameter, StringComparison.InvariantCultureIgnoreCase) == 0;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (targetType.IsAssignableFrom(typeof(Boolean)) && targetType.IsAssignableFrom(typeof(String)))
throw new ArgumentException("EnumConverter can only convert back value from a string or a boolean.");
if (!targetType.IsEnum)
throw new ArgumentException("EnumConverter can only convert value to an Enum Type.");
if (value.GetType() == typeof(String))
{
return Enum.Parse(targetType, (String)value, true);
}
//We have a boolean, as for binding to a checkbox. we use parameter
if ((Boolean)value)
return Enum.Parse(targetType, (String)parameter, true);
return null;
}
}
Обратите внимание, что Я не привязываю данные к списку перечислений для генерации переключателей, я сделал их вручную. Если вы хотите заполнить список переключателей с помощью привязки, я думаю, вам нужно изменить привязку IsChecked
на MultiBinding
, которая привязывает как текущее значение, так и значение радио. значение enum, поскольку вы не можете использовать привязку для ConverterParameter
.
Привязать список к ItemsSource ListBox со списком объекты, у которых есть свойство Name (это может измениться)
<ListBox Name="RadioButtonList">
<ListBox.ItemTemplate >
<DataTemplate >
<RadioButton GroupName="radioList" Tag="{Binding}" Content="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
important GroupName = "radioList"
Я обманул:
Мое решение заключалось в том, чтобы привязать список программно, поскольку это все, что, казалось, сработало для меня:
if (mUdData.Telephony.PhoneLst != null)
{
lbPhone.ItemsSource = mUdData.Telephony.PhoneLst;
lbPhone.SelectedValuePath = "ID";
lbPhone.SelectedValue = mUdData.Telephony.PrimaryFaxID;
}
XAML выглядит так:
<ListBox.ItemTemplate >
<DataTemplate >
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<RadioButton
IsChecked="{Binding Path=PrimaryPhoneID}"
GroupName="Phone"
x:Name="rbPhone"
Content="{Binding Path=PrimaryPhoneID}"
Checked="rbPhone_Checked"/>
<CheckBox Grid.Column="2" IsEnabled="False" IsChecked="{Binding Path=Active}" Content="{Binding Path=Number}" ></CheckBox>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
И в моем случае чтение значения переключателя при его выборе выглядит так:
private void rbPhone_Checked(object sender, RoutedEventArgs e)
{
DataRowView dvFromControl = null;
dvFromControl = (DataRowView)((RadioButton)sender).DataContext;
BindData.Telephony.PrimaryPhoneID = (int)dvFromControl["ID"];
}
Надеюсь, что это поможет кто-то.