简体   繁体   English

StatusBar 绑定到 TabControl 活动选项卡中 UserControl 中的属性

[英]StatusBar Bind to property in UserControl in active tab of TabControl

I made this Minimal, Complete, and Verifiable example of the challenge I'm facing.我制作了这个最小、完整且可验证的示例来说明我面临的挑战。 It works but is definitely not MVVM and is nothing more than a hack.它可以工作,但绝对不是 MVVM,只不过是一种 hack。

It updates the status bar based on some property changing in the user control.它根据用户控件中的某些属性更改更新状态栏。 It also updates when the user changes the tab.当用户更改选项卡时,它也会更新。 For the real deal, it will be displaying a records count (how many data rows are displayed in each tab).对于真正的交易,它将显示记录计数(每个选项卡中显示多少数据行)。

There must be a cleaner way of doing this...必须有一种更清洁的方法来做到这一点......

How can this be done using MVVM?如何使用 MVVM 做到这一点?

Note: In my actual implementation, the data context for each user control is different.注意:在我的实际实现中,每个用户控件的数据上下文是不同的。 So if someone has a suggestion for binding that involves a similar data context, please take that into consideration.因此,如果有人对涉及类似数据上下文的绑定提出建议,请考虑这一点。

Main Window XAML主窗口 XAML

<Window x:Class="TabControlStatusBarBinding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TabControlStatusBarBinding"
        Title="MainWindow" Height="150" Width="300"
        x:Name="Window">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="auto"/>
        </Grid.RowDefinitions>
        <TabControl Grid.Row="0">
            <TabItem Header="Tab1">
                <local:UserControl1 x:Name="UC1_A"/>
            </TabItem>
            <TabItem Header="Tab2">
                <local:UserControl1 x:Name="UC1_B" />
            </TabItem>
            <TabItem Header="Tab3">
                <local:UserControl1 x:Name="UC1_C"/>
            </TabItem>
        </TabControl>
        <StatusBar Grid.Row="1">
            <TextBlock Text="{Binding DP_StatusBarText, ElementName=Window, FallbackValue='No Updates'}"/>
        </StatusBar>
    </Grid>
</Window>

User Control XAML用户控制 XAML

<UserControl x:Name="MyUserControl" x:Class="TabControlStatusBarBinding.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" d:DesignHeight="50" d:DesignWidth="90" GotFocus="MyUserControl_GotFocus">
    <Grid Background="Gray">
        <TextBox x:Name="UC1" Text="test" HorizontalAlignment="Center" VerticalAlignment="Center" TextChanged="UC1_TextChanged"/>
    </Grid>
</UserControl>

Main Window Code Behind背后的主窗口代码

namespace TabControlStatusBarBinding
{
    public partial class MainWindow : Window
    {
        public static DependencyProperty dp_StatusBarText = DependencyProperty.Register("DP_StatusBarText", typeof(string), typeof(MainWindow));
        public string DP_StatusBarText
        {
            get { return (string)GetValue(dp_StatusBarText); }
            set { SetValue(dp_StatusBarText, value); }
        }
        public MainWindow()
        {
            InitializeComponent();

            DP_StatusBarText = "Main window loaded";

            UC1_A.StatusUpdated += MyEventHandlerFunction_StatusUpdated;
            UC1_B.StatusUpdated += MyEventHandlerFunction_StatusUpdated;
            UC1_C.StatusUpdated += MyEventHandlerFunction_StatusUpdated;
        }
        public void MyEventHandlerFunction_StatusUpdated(object sender, EventArgs e)
        {
            DP_StatusBarText = (string)sender;
        }
    }
}

User Control Code Behind背后的用户控制代码

namespace TabControlStatusBarBinding
{
    public partial class UserControl1 : UserControl
    {
        public event EventHandler StatusUpdated;
    
        public UserControl1()
        {
            InitializeComponent();
        }

        private void RaiseStatusUpdatedEvent(string SendText)
        {
            if (this.StatusUpdated != null)
                this.StatusUpdated(SendText, new EventArgs());
        }

        private void UC1_TextChanged(object sender, TextChangedEventArgs e)
        {
            RaiseStatusUpdatedEvent(UC1.Text);
        }

        private void MyUserControl_GotFocus(object sender, RoutedEventArgs e)
        {
            RaiseStatusUpdatedEvent(UC1.Text);
        }
    }
}

Well your example only uses views - no models, no viewmodels, so not very clear what are your problems with MVVM :) But I'll try to help you introducing some data in your example.那么你的例子只使用视图 - 没有模型,没有视图模型,所以不太清楚你的MVVM 有什么问题 :) 但我会尽力帮助你在你的例子中介绍一些数据。

First, just simple data item.首先,只是简单的数据项。

public class TestDataItem : INotifyPropertyChanged {
    public int ID { get; set; }
    private string _text;
    public string Text
    {
        get { return _text; }
        set
        {
            if (value == _text) return;
            _text = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

UserControl1.用户控件1。 Just binds textbox Text to model Text property.只需将文本框 Text 绑定到模型 Text 属性。 Codebehind is empty.代码隐藏是空的。

<UserControl x:Class="WpfApplication2.UserControl1"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"              
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
    <Grid Background="Gray">
        <TextBox Text="{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
</UserControl>

Window.窗户。 Tabs in tab control are now bound to a list of data items.选项卡控件中的选项卡现在绑定到数据项列表。 Tab content is just UserControl1 (it will inherit data context).选项卡内容只是 UserControl1(它将继承数据上下文)。

<Window x:Class="WpfApplication2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"                
    xmlns:wpfApplication2="clr-namespace:WpfApplication2"
    mc:Ignorable="d"
    Title="MainWindow" Height="500" Width="500">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="auto"/>
    </Grid.RowDefinitions>
    <TabControl x:Name="tabControl" Grid.Row="0" ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}">
        <TabControl.ItemTemplate>
            <DataTemplate DataType="wpfApplication2:TestDataItem">
                <TextBlock Text="{Binding ID}" />
            </DataTemplate>
        </TabControl.ItemTemplate>
        <TabControl.ContentTemplate>
            <DataTemplate DataType="wpfApplication2:TestDataItem">
                <wpfApplication2:UserControl1 />
            </DataTemplate>
        </TabControl.ContentTemplate>
    </TabControl>
    <StatusBar Grid.Row="1">
        <TextBlock Text="{Binding SelectedItem.Text, FallbackValue='No Updates'}"/>
    </StatusBar>
</Grid>
</Window>

Window code-behind:窗口代码隐藏:

public partial class MainWindow : Window {
    public MainWindow() {
        InitializeComponent();
        this.DataContext = new MainViewModel();
    }
}

View model:查看型号:

 public class MainViewModel : INotifyPropertyChanged {
    public IEnumerable<TestDataItem> Items => new[] {
            new TestDataItem() {ID = 100, Text = "item1"},
            new TestDataItem() {ID = 200, Text = "item2"},
            new TestDataItem() {ID = 300, Text = "item3"}
        };

    private string _statusText = "No data selected";
    public string StatusText
    {
        get { return _statusText; }
        set
        {
            if (value == _statusText) return;
            _statusText = value;
            OnPropertyChanged();
        }
    }

    private TestDataItem _selectedItem;
    public TestDataItem SelectedItem
    {
        get { return _selectedItem; }
        set
        {
            if (Equals(value, _selectedItem)) return;
            _selectedItem = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

So we just bind status to SelectedItem.Text and done.所以我们只是将状态绑定到 SelectedItem.Text 并完成。

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

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