XAML中正确的代码隐藏对象数据绑定?

时间:2013-09-25 12:49:45

标签: c# wpf xaml data-binding

我正在将代码隐藏(C#)中的对象绑定到我的XAML,方法是为XAML控件命名,并在代码隐藏中设置DataContext。

public partial class SmsControl: UserControl
{
    private readonly DataOrganizer _dataOrganizer;
    public FunctionalTester _funcTester;

    public SmsControl()
    {
        InitializeComponent();

        _dataOrganizer = new DataOrganizer();
        _funcTester = new FunctionalTester();

        // Set the datacontext appropriately
        grpModemInitialization.DataContext = _funcTester;
    }

    private async void Button_Click_2(object sender, RoutedEventArgs e)
    {
        await _funcTester.Test();
    }
}

我的XAML ......

 <!-- SMS Test Modem Initialization GroupBox -->
    <GroupBox x:Name="grpModemInitialization" Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="3"  Style="{StaticResource groupboxViewItem}">
        <GroupBox.Header>
            <Label Content="SMS Test Modem Initialization" Style="{StaticResource boldHeaderItem}"/>
        </GroupBox.Header>

        <!-- SMS Test Modem Initialization Grid -->
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="50"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>

            <Label Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" Content="COM:" Style="{StaticResource boldHeaderItem}" />
            <ComboBox Grid.Column="1" Grid.Row="0" Grid.RowSpan="2" Style="{StaticResource comboBoxItem}" ItemsSource="{Binding AvailableCommPorts}" SelectedItem="{Binding SelectedCommPort}" />
            <Label Grid.Column="2" Grid.Row="0" Content="Modem Ready:" Style="{StaticResource boldHeaderItem}" />
            <Label Grid.Column="2" Grid.Row="1" Content="RSSI:" Style="{StaticResource boldHeaderItem}" />
            <Label Content="{Binding ModemReady}" Grid.Column="3" Grid.Row="0"  HorizontalContentAlignment="Left" VerticalAlignment="Center"/>
            <Label Content="{Binding ModemRssi}" Grid.Column="3" Grid.Row="1" HorizontalContentAlignment="Left" VerticalAlignment="Center" />
            <Label Grid.Column="4" Grid.Row="0" Content="Modem #:" Style="{StaticResource boldHeaderItem}"/>
            <Button Grid.Column="4" Grid.Row="1" Grid.ColumnSpan="2" Content="Initialize" />
            <Label Content="{Binding ModemNumber}" Grid.Column="5" Grid.Row="0" HorizontalContentAlignment="Left" VerticalAlignment="Center"/>
        </Grid>
    </GroupBox>

上面的代码运行正常 - 没问题。我要问的是,如果有办法在XAML中设置GroupBox的DataContext,引用我的_funcTester对象,而不是在代码隐藏中设置DataContext?我问的原因是因为不同的控件需要绑定到代码隐藏中的不同对象,我找不到如何这样做的好资源,除非我在上面显示(给每个控件提供一个“x:Name”) XAML控制并在代码隐藏中设置DataContext。任何帮助表示赞赏!谢谢!

2 个答案:

答案 0 :(得分:1)

您不希望在代码隐藏中按名称引用UI元素。实际上,任何时候你都可以避免命名一个对象save a little in performance。通过将应用程序设置为正确使用MVVM,您可以获得性能,可读性,可维护性和代码分离。

您希望进一步抽象出来以使用MVVM模式。你正确地进行了绑定,但考虑了模式。你的观点都是正确的。考虑添加一个类,该类包含当前在代码隐藏中定义的属性以及在事件处理程序中调用的方法。

public class ViewModel : INotifyPropertyChanged
{
    private FunctionalTester _funcTester;
    public FunctionalTester FuncTester
    {
        get
        {
            return _funcTester;
        }
        set
        {
            _funcTester = value;
            OnPropertyChanged( "FuncTester" );
        }
    }

    public async void TestAsync( )
    {
        await _funcTester.Test( );
    }
}

对FuncTester的绑定只是SomeProperty="{Binding FuncTester}",因为该对象被设置为视图的DataContext。一篇体面的文章,扩展了这个想法is found here

为了简洁,显然遗漏了一些内容(例如INotifyPropertyChanged实现和您定义的其他属性)。但只需创建此类并将其指定为视图模型。然后,UI(Xaml和代码隐藏)只能真正处理UI,而ViewModel真正处理数据和逻辑。很好的分离。对于您的事件处理程序,只需调用((ViewModel)this.DataContext).Test( );即可即插即用ViewModel来动态更改功能。希望这有帮助!

答案 1 :(得分:0)

只需设置DataContext of whole UserControl to self

构造函数中的

this.DataContext = this;

然后为_functinTester定义属性

public FunctionalTester FuncTester { get {return _funcTester} };

现在你的xaml可以做到

<GroupBox x:Name="grpModemInitialization" DataContext="{Binding FuncTester}"/>

这样,因为您为整个usercontrol设置了DataContext,所以可以将任何控件绑定到该DataContext中的任何属性