【问题标题】:Proper Code-Behind Object Data Binding in XAML?XAML 中正确的代码隐藏对象数据绑定?
【发布时间】:2013-09-25 12:49:45
【问题描述】:

我目前正在通过为 XAML 控件命名并在代码隐藏中设置 DataContext 将我的代码隐藏 (C#) 中的对象绑定到我的 XAML。

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:名称” XAML 控制并在代码隐藏中设置 DataContext)。任何帮助表示赞赏!谢谢!

【问题讨论】:

    标签: c# wpf xaml data-binding


    【解决方案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 来动态更改功能。希望这会有所帮助!

    【讨论】:

    • 如何将您的 ViewModel 对象设置为 GroupBox/View 的 DataContext?我想这就是我有点困惑的地方。
    【解决方案2】:

    只需设置DataContext of whole UserControl to self 即做

    this.DataContext = this; 在构造函数中。

    然后定义 _functinTester 的属性

    public FunctionalTester FuncTester { get {return _funcTester} };
    

    现在你可以在你的 xaml 中做

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

    通过这种方式,由于您为整个用户控件设置了 DataContext,因此您可以将任何控件绑定到该 DataContext 中的任何属性

    【讨论】:

    • 如果您希望(或需要)避免对 UserControl 的 DataContext 进行硬编码,您可以将绑定编写为 DataContext="{Binding FuncTester, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}
    猜你喜欢
    • 1970-01-01
    • 2012-07-15
    • 2010-12-14
    • 2012-07-13
    • 1970-01-01
    • 2019-06-07
    • 1970-01-01
    • 1970-01-01
    • 2015-03-25
    相关资源
    最近更新 更多