WPF - 使用两个不同窗口中的Label.Content在两个CheckBoxes的内容之间绑定

时间:2017-03-03 14:55:34

标签: c# wpf data-binding

我的项目中有两个窗口(MainWindow和一个小窗口,用于MainWindow控件的某些属性)。在MainWindow的一个Tab中,有一个Grid分为十列。在每个列中都有一些控件。下面是我的项目的示例代码。

如果我将Label(MainWindow)中的Period(CheckBox)检查为“Period”,并且当我检查频率(PropertiesWindow中的CheckBox)时Label(MainWindow)为“Frequency”,我想要。

当我选中PropertiesWindow(Period或Frequency)中的一个复选框时,我希望MainWindow上的Label(lb_freq1)根据选中的CheckBox的内容更改其内容。 (此外,所选单位要在time_div1(标签)处显示)。

第一个解决方案:

XAML MainWindow:

<Window x:Class="wpf1.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:local="clr-wpf1"
    mc:Ignorable="d"
    Title="wpf1" Height="720" Width="1280" WindowStartupLocation="CenterScreen" Icon="kkk.bmp" Background="#FFE0E0E0" Foreground="#FF49A81D" BorderBrush="#FFB93838" >
    <Grid>
        <TabControl x:Name="tabControl">
            <TabItem Header="Tab1">
                <Grid>
                    <StackPanel>
                        <Label x:Name="lb_freq1" Content="Period" HorizontalAlignment="Center" Margin="0,10,0,0" />
                        <StackPanel Orientation="Horizontal" Margin="0" HorizontalAlignment="Center">
                            <TextBox x:Name="txt_freq1" Width="50" Height="20" HorizontalContentAlignment="Right" BorderThickness="1,1,0,1" HorizontalAlignment="Left" VerticalContentAlignment="Center"/>
                            <Label x:Name="time_div1" Content="us" Width="20" BorderThickness="0,1,1,1" Margin="0" HorizontalAlignment="Right" Height="20" Padding="0" BorderBrush="#FFABADB3" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" />
                        </StackPanel>
                        <Label x:Name="lb_width1" Content="Pulse Width" HorizontalAlignment="Center" Margin="0,10,0,0" />
                        <StackPanel Orientation="Horizontal" Margin="0" HorizontalAlignment="Center">
                            <TextBox x:Name="txt_width1" Width="50" Height="20" HorizontalContentAlignment="Right" BorderThickness="1,1,0,1" HorizontalAlignment="Left"/>
                            <Label x:Name="pv_div1" Content="us" Width="20" BorderThickness="0,1,1,1" Margin="0" HorizontalAlignment="Right" Height="20" Padding="0" BorderBrush="#FFABADB3" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" />
                        </StackPanel>
                        <Button x:Name="Properties1" Content="Properties" Margin="10,30,10,10" HorizontalAlignment="Center" BorderBrush="Blue" Click="Properties1_Click" />
                    </StackPanel>
                </Grid>
            </TabItem>
        </TabControl>
    </Grid>
</Window>

EDITED MainWindow背后的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Globalization;
using System.ComponentModel;

namespace wpf1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        ViewModel viewModel = new ViewModel();

        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;
        }

        private void Properties1_Click(object sender, RoutedEventArgs e)
        {
            string res1 = lb_freq1.Content.ToString();
            string res3 = time_div1.Content.ToString();

            var newWindow = new PWMProperties();
            newWindow.Owner = this;
            newWindow.ShowDialog();

            string result1 = newWindow.Value1;
            if (result1 == null)
            {
                lb_freq1.Content = res1;
            }
            else
            {
                lb_freq1.Content = result1;
            }

            string result3 = newWindow.Unit1;
            if (result3 == null)
            {
                time_div1.Content = res3;
            }
            else
            {
                time_div1.Content = result3;
            }
        }
    }
}

XAML PropertiesWindow:

<Window x:Class="wpf1.PWMProperties"
    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:local="clr-namespace:wpf1"
    mc:Ignorable="d"
    Title="Properties" Height="335" Width="285" ResizeMode="NoResize" BorderThickness="0" WindowStartupLocation="CenterOwner">
<Window.Resources>
    <local:BoolConverter2 x:Key="Converter"></local:BoolConverter2>
    <local:BoolConverter x:Key="Reverse"></local:BoolConverter>
</Window.Resources>
    <Grid>
        <StackPanel VerticalAlignment="Top" Margin="0,10,0,0" HorizontalAlignment="Center">
            <StackPanel Orientation="Horizontal" Margin="0,0,0,20">
                <StackPanel Margin="0,0,49,0">
                    <RadioButton x:Name="SelectPeriod" Content="Period" Margin="0,0,0,0" Click="SelectPeriod_Click" />
                    <ComboBox x:Name="PeriodUnits" Padding="3,2,2,2" IsReadOnly="True" IsEditable="True" Text="us" IsEnabled="{Binding ElementName=SelectPeriod, Path=IsChecked}" SelectionChanged="PeriodUnits_SelectionChanged"
                    ItemsSource="{Binding PeriodComboBoxItems}">
                    </ComboBox>
                </StackPanel>
                <StackPanel Margin="20,0,0,0">
                    <RadioButton x:Name="SelectFrequency" Content="Frequency" Click="SelectFrequency_Click" />
                    <ComboBox x:Name="FrequencyUnits" Padding="3,2,2,2" IsReadOnly="True" IsEditable="True" Text="Hz" IsEnabled="{Binding ElementName=SelectFrequency, Path=IsChecked}" SelectionChanged="FrequencyUnits_SelectionChanged"
                    ItemsSource="{Binding FrequencyComboBoxItems}">
                    </ComboBox>
                </StackPanel>
            </StackPanel>
        </StackPanel>
        <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" Margin="0">
            <Button x:Name="OkButton" Content="OK" Margin="135,5,10,5" Click="OkButton_Click" Width="60" />
            <Button x:Name="CancelButton" Content="Cancel" Click="CancelButton_Click" Width="60" Margin="0,5,10,5" />
        </StackPanel>
    </Grid>
</Window>

EDITED PropertyWindow背后的代码:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.ComponentModel;
using System.IO;
using System.Xml;
using System.Windows.Markup;

namespace wpf1
{
    /// <summary>
    /// Interaction logic for Analog.xaml
    /// </summary>
    public partial class PWMProperties : Window
    {
        public ObservableCollection<string> PeriodComboBoxItems { get; set; }
        public ObservableCollection<string> FrequencyComboBoxItems { get; set; }
        public ObservableCollection<string> PulseWidthComboBoxItems { get; set;}

        public PWMProperties()
        {
            InitializeComponent();
            this.DataContext = this;
            this.PeriodComboBoxItems = new ObservableCollection<string>() { "us", "ms", "s" };
            this.FrequencyComboBoxItems = new ObservableCollection<string>() { "Hz", "kHz", "MHz" };
            this.PulseWidthComboBoxItems = new ObservableCollection<string>() { "us", "ms", "s" };
        }

        string val1, val2, unit1, unit2;

        private void OkButton_Click(object sender, RoutedEventArgs e)
        {
            if (SelectPeriod.IsChecked == true)
            {
                val1 = "Period";
                if (unit1 == null || unit1!="ms") unit1 = "us";
            }

            if (SelectFrequency.IsChecked == true)
            {
                val1 = "Frequency";
                if (unit1 == null || unit1!="kHz") unit1 = "Hz";
            }

            DialogResult = true;
        }

        private void CancelButton_Click(object sender, RoutedEventArgs e)
        {
            DialogResult = false;
        }

        public string Value1 { get { return val1; } }

        public string Value2 { get { return val2; } }

        public string Unit1 { get { return unit1; } }

        public string Unit2 { get { return unit2; } }

        private void PeriodUnits_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            unit1 = PeriodUnits.SelectedItem.ToString();
        }

        private void FrequencyUnits_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            unit1 = FrequencyUnits.SelectedItem.ToString();
        }

    }

    public class BoolConverter2 : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            bool v = (bool)value;
            return v;
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new System.NotSupportedException();
        }
    }
}

第二种可能的解决方案:

然后,我在我的MainWindow代码中添加了一个ViewModel:

public class ViewModel : INotifyPropertyChanged
    {
        private string _value1 = "Period";

        public event PropertyChangedEventHandler PropertyChanged;

        public string Value1
        {
            get { return _value1; }
            set
            {
                _value1 = value;
                OnPropertyChanged("Value1");
            }
        }

        protected virtual void OnPropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

因此,删除了PropertiesWindow背后的大部分代码,并在MainWindow中使用Binding来更改lb_freq1(Label)。

<Label x:Name="lb_freq1" Content="{Binding Value1, Mode=TwoWay}" HorizontalAlignment="Center" Margin="0,10,0,0" />

我不知道如何从那个州继续。我是WPF和C#的新手,如果有人能以任何方式帮助我,我将感激不尽。

主要问题

我已经编辑了我的第一个解决方案,所以如果有人可以看看。我现在设法做的几乎就是我想要的。但有个问题。我想,当我点击OK.Button时,我在Properties.Window上做的“设置”应该改变MainWindow的标签。虽然,当我单击右上角的Cancel.Button或Close.Button时,在Properties.Window上所做的任何更改都不应更改MainWindow上的标签。

此外,当我关闭Properties.Window,然后再次打开它时,CheckBoxes和ComboBox.SelectedItems需要具有与Properties.Window关闭时相同的状态。但这不会发生。

1 个答案:

答案 0 :(得分:0)

您应该正确设置两个窗口的DataContext。目前,您正在多个位置设置和覆盖它。以下是我的建议:

在您的窗口中绑定时使用ElementName,即wpf1.PWMPropertieswpf1.MainWindow,只要您想要绑定到其中的媒体资源。换句话说,给他们一个名字并与他们绑定。例如:

<Window x:Class="wpf1.PWMProperties"
   .....
  Name="owner">
   .....
            <StackPanel Margin="0,0,49,0">
                .....
                ItemsSource="{Binding Path=PeriodComboBoxItems, ElementName=owner}">
            </StackPanel>

使用DataContext绑定到ViewModel中的Value1。将两个Windows的DataContext设置为ViewModel的实例:

public partial class MainWindow : Window
{
    ViewModel viewModel = new ViewModel();

    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = viewModel;
    }

    private void Properties1_Click(object sender, RoutedEventArgs e)
    {
        var newWindow = new PWMProperties();
        newWindow.Owner = this;
        newWindow.DataContext = viewModel; 
        newWindow.Show(); 
    }
}