简体   繁体   English

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

[英]Proper Code-Behind Object Data Binding in XAML?

I am currently binding an object in my code-behind (C#) to my XAML by giving a name to the XAML control, and setting the DataContext in the code-behind. 我目前通过给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();
    }
}

And my XAML... 还有我的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>

The code above works fine - no problems. 上面的代码工作正常-没问题。 What I'm asking is, if there is a way to set the DataContext of the GroupBox in XAML, referencing my _funcTester object, instead of setting the DataContext in the code-behind? 我要问的是,是否有办法在XAML中设置GroupBox的DataContext,引用我的_funcTester对象,而不是在后面的代码中设置DataContext? The reason I ask, is because different controls need to be bound to different objects in the code-behind and I'm not finding good resources on how to do so, except as I show above (giving a "x:Name" to each XAML control and setting the DataContext in code-behind). 我问的原因是,因为需要将不同的控件绑定到后台代码中的不同对象上,因此我没有找到很好的方法,除非如上所示(为每个对象都赋予“ x:Name”) XAML控件并在代码后面设置DataContext)。 Any help is appreciated! 任何帮助表示赞赏! Thanks! 谢谢!

You don't want to reference UI elements by name in the code-behind. 您不想在后面的代码中按名称引用UI元素。 Actually any time you can avoid naming an object you save a little in performance . 实际上,任何时候您都可以避免命名一个对象,从而可以节省一些性能 And by setting up your app to use MVVM properly, you gain in performance, readability, maintainability, and code separation. 通过设置您的应用程序以正确使用MVVM,您可以获得性能,可读性,可维护性和代码分离性。

You want to abstract things further to use the MVVM pattern. 您想使用MVVM模式进一步抽象事物。 You're doing your bindings correctly but consider the pattern. 您正在正确地进行绑定,但是请考虑模式。 Your view is all correct. 您的观点都是正确的。 Consider adding a class that holds the properties defined currently in your code-behind and the methods called in your event handlers. 考虑添加一个类,该类包含当前在代码隐藏中定义的属性以及事件处理程序中调用的方法。

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( );
    }
}

A binding to the FuncTester would simply be SomeProperty="{Binding FuncTester}" because the object is set as the DataContext of your view. 与FuncTester的绑定将只是SomeProperty SomeProperty="{Binding FuncTester}"因为该对象被设置为视图的DataContext。 A decent article that expands on this idea is found here . 在此可以找到有关此想法的扩展文章。

Obviously left out some things (like INotifyPropertyChanged implementation and other properties you've defined) for brevity. 为了简洁起见,显然遗漏了一些东西(例如INotifyPropertyChanged实现和您定义的其他属性)。 But just make this class and assign it as your view model. 但是只需创建此类并将其分配为您的视图模型即可。 Then the UI (the Xaml and the code-behind) only really deal with the UI and the ViewModel really deals with the data and logic. 然后,UI(Xaml和后面的代码)仅真正处理UI,而ViewModel真正处理数据和逻辑。 Great separation. 大分隔。 For your event handler, just call ((ViewModel)this.DataContext).Test( ); 对于事件处理程序,只需调用((ViewModel)this.DataContext).Test( ); and you can plug-and-play your ViewModel's to change functionality on the fly. 您可以即插即用的ViewModel即时更改功能。 Hope this helps! 希望这可以帮助!

Just set the DataContext of whole UserControl to self ie do 只需将DataContext of whole UserControl to selfDataContext of whole UserControl to self设置DataContext of whole UserControl to self

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

Then define the Property for _functinTester 然后为_functinTester定义属性

public FunctionalTester FuncTester { get {return _funcTester} };

Now in your xaml you can do 现在,您可以在xaml中执行

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

In this way since you have the DataContext set for your whole usercontrol, you can bind any control to any property within that DataContext 这样,由于为整个用户控件设置了DataContext,因此可以将任何控件绑定到该DataContext中的任何属性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM