2016-10-30 3 views
0

"EDIT"Databind in WPF

Was ich will, ist zu erreichen, so etwas wie -

MainWindow.xaml einen Button enthält, ein Kombinationsfeld und ein Contentcontrol. UserControl-A und UserControl-C enthalten beide ein ContentControl. UserControl-B und UserControl-D enthalten beide einen TextBlock.

UserControl-B ist Inhalt von ContentControl Enthalten in UserControl-A. UserControl-D ist Inhalt von ContentControl Enthalten in UserControl-C.

UserControl-A Oder UserControl-C ist Inhalt von ContentControl Enthalten in MainWindow.xaml auf einen Klick auf den Button.

Bei Änderung in SelectedValue von Combobox Update TextBlock von UserControl-B oder UserControl-D.

"EDIT"

Neben MainWindow.xaml, App.xaml und App.config Ich habe MainContent1.xaml, MainContent2.xaml, ComboItems.cs und zwei Unterordner Sub1 und Sub2, jeder von ihnen enthält eine einzelne Datei namens S1.xaml in meinem Projekt.

meines Code Alle in ComboItems.cs geschrieben as -

namespace MultiBinding 
{ 
public class Item 
{ 
    public string Name { get; set; } 
    public int Id { get; set; } 
} 

public class ComboItems 
{ 
    public ComboItems() 
    { 
     Items = new List<Item>(3); 
     for (int i = 1; i < 4; i++) 
      Items.Add(new Item { Id = i, Name = "Name " + i });   
    } 
    public List<Item> Items { get; set; } 
} 

public class ButtonContent : INotifyPropertyChanged 
{ 
    public ICommand MyCommand { get; set; } 
    private string _content; 

    public ButtonContent() 
    { 
     _content = "First"; 
     MyCommand = new Command(Do, CanDo); 
    } 

    public string Content 
    { 
     get { return _content; } 
     set { _content = value; OnChange("Content"); } 
    } 

    private bool CanDo(object parameter) => true;  
    private void Do(object parameter) => Content = Content == "First" ? "Second" : "First"; 
    public event PropertyChangedEventHandler PropertyChanged; 
    private void OnChange(string name) => 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); 
} 

public class Command : ICommand 
{ 
    private Action<object> Do; 
    private Func<object, bool> CanDo; 
    public Command(Action<object> Do, Func<object, bool> CanDo) 
    { 
     this.Do = Do; 
     this.CanDo = CanDo; 
    } 
    public event EventHandler CanExecuteChanged; 
    public bool CanExecute(object parameter) => true; 
    public void Execute(object parameter) => Do(parameter); 
} 

public class SomeText 
{ 
    public static string Text1 { get; set; } 
    public static string Text2 { get; set; } 
} 


public class Converter : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
    { 
     switch (values[1].ToString()) 
     { 
      case "1": SomeText.Text1 = SomeText.Text2 = "Selected Item is 1"; break; 
      case "2": SomeText.Text1 = SomeText.Text2 = "Selected Item is 2"; break; 
      case "3": SomeText.Text1 = SomeText.Text2 = "Selected Item is 3"; break; 
     } 

     if (values[0].ToString() == "First") return new MainContent1(); 
     else return new MainContent2();  
    } 

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

}

Inhalt des MainWindow.xaml ist -

<Window x:Class="MultiBinding.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:MultiBinding"> 

<Window.Resources> 
    <local:ComboItems x:Key="cboItems" /> 
    <local:Item x:Key="Item" /> 
    <local:Converter x:Key="convert" /> 
    <local:ButtonContent x:Key="content"/> 
</Window.Resources> 

<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="10*"/> 
     <RowDefinition Height="90*"/> 
    </Grid.RowDefinitions> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="1*"/> 
     <ColumnDefinition Width="1*"/> 
    </Grid.ColumnDefinitions> 
    <ComboBox x:Name="combo" 
       DataContext="{Binding Source={StaticResource Item}}" 
       ItemsSource="{Binding Path=Items, Source={StaticResource cboItems}}" 
       DisplayMemberPath="Name" 
       SelectedValuePath="Id" 
       SelectedValue="{Binding Path=Id}"/> 

    <Button x:Name="butt" Grid.Column="1" 
      DataContext="{Binding Source={StaticResource content}}" 
      Content="{Binding Path=Content}" 
      Command="{Binding Path=MyCommand}"/> 

    <ContentControl Grid.Row="1" Grid.ColumnSpan="2"> 
     <ContentControl.Content> 
      <MultiBinding Converter="{StaticResource convert}"> 
       <Binding ElementName="butt" Path="Content"/> 
       <Binding ElementName="combo" Path="SelectedValue"/> 
      </MultiBinding> 
     </ContentControl.Content> 
    </ContentControl> 
</Grid> 

Inhalt des MainContent1.xaml ist -

<UserControl x:Class="MultiBinding.MainContent1" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:sub="clr-namespace:MultiBinding.Sub1"> 
<UserControl.Resources> 
    <sub:S1 x:Key="s1"/> 
</UserControl.Resources> 
<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="Auto"/> 
     <RowDefinition/> 
    </Grid.RowDefinitions> 

    <TextBlock FontSize="20" Text="On Main ContentControl No. 1"/> 
    <ContentControl 
     Content="{Binding Source={StaticResource s1}}" 
     Grid.Row="1"/> 
</Grid> 

MainContent2.xaml exakt gleichen Code enthält wie oben, außer

xmlns:sub="clr-namespace:MultiBinding.Sub2" 

Inhalt des S1.xaml unter Ordner Sub1 wird -

<UserControl x:Class="MultiBinding.Sub1.S1" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:main="clr-namespace:MultiBinding"> 
<UserControl.Resources> 
    <main:SomeText x:Key="MyText"/> 
</UserControl.Resources> 
<Grid Background="Bisque"> 
    <TextBlock Text="{Binding Text1, Source={StaticResource MyText}}" /> 
</Grid> 

S1.xaml unter Ordner Sub2 dem von Sub1 Ordner ähnlich ist, außer

<TextBlock Text="{Binding Path=Text2, Source={StaticResource MyText}}" /> 

alles funktioniert wie auf diese Weise zu erwarten.

Gibt es ein Problem mit statischen Schlüsselwort vor Text1 und Text2 Eigenschaften von SomeText-Klasse in ComboItems.cs?

Wie kann ich dieselbe Funktionalität ohne statische Eigenschaften der SomeText-Klasse erreichen?

+0

Das ist eine Menge Code, um durch zu verstehen, was Sie versuchen zu tun. Sie würden wahrscheinlich bessere Hilfe bekommen, wenn Sie die Frage an die Spitze schreiben und etwas Zeit in die Reduzierung des Quellcodes investieren würden. HTH – LosManos

+0

Lange Frage, kurze Antwort - MVVM-Muster verwenden. Sie können verschiedene Steuerelemente mit einem gemeinsamen Datenmodell verknüpfen – benPearce

+0

@benPearce Bin ich in meiner Antwort dem MVVM-Muster richtig? –

Antwort

0

ich entfernt haben "ComboItems und Converter" Klassen von ComboItems.cs, umbenannt in "ButtonContent" Klasse als "MyCode" und setzte es wie folgt -

public class MyCode : INotifyPropertyChanged 
{ 
    //Fields 
    private Sub1.S1 _s1; 
    private Sub2.S1 _s2; 
    private MainContent1 _m1; 
    private MainContent2 _m2; 
    private object _mainContent; 
    private object _subContent; 
    private int _selectedIndex; 

    //Properties 
    public string Text { get; set; } 
    public List<Item> Items { get; set; } 
    public ICommand MyCommand { get; set; } 
    public string Content { get; set; } 
    public object MainContent 
    { 
     get { return _mainContent; } 
     set { _mainContent = value; OnChange("MainContent"); } 
    } 
    public object SubContent 
    { 
     get { return _subContent; } 
     set { _subContent = value; OnChange("SubContent"); } 
    } 

    public int SelectedIndex 
    { 
     get { return _selectedIndex; } 
     set 
     { 
      _selectedIndex = value; 
      //Action on selection change 
      switch (_selectedIndex) 
      { 
       case 0: Text = "Selected Item is 1"; break; 
       case 1: Text = "Selected Item is 2"; break; 
       case 2: Text = "Selected Item is 3"; break; 
      } 
      OnChange("Text"); 
     } 
    } 

    //Constructor 
    public MyCode() 
    { 
     Content = "First"; 
     MyCommand = new Command(Do, CanDo); 
     _m1 = new MainContent1(); 
     _m2 = new MainContent2(); 
     _s1 = new Sub1.S1(); 
     _s2 = new Sub2.S1(); 
     MainContent = _m1; 
     SubContent = _s1; 
     Items = new List<Item>(3); 
     for (int i = 1; i < 4; i++) 
      Items.Add(new Item { Id = i, Name = "Name " + i }); 
     SelectedIndex = 0; 
    } 

    //Action on Button Click     
    private void Do(object parameter) 
    { 
     if(Content == "First") 
     { 
      MainContent = _m2; 
      SubContent = _s2; 
      Content = "Second"; 
     } 
     else 
     { 
      MainContent = _m1; 
      SubContent = _s1; 
      Content = "First";    
     } 
     OnChange("Content"); 
    } 

    private bool CanDo(object parameter) => true; 
    //Inotify 
    public event PropertyChangedEventHandler PropertyChanged; 
    private void OnChange(string name) => 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); 
} 

Changed MainWindow.xaml zu -

<Window.Resources> 
    <local:MyCode x:Key="Code"/> 
</Window.Resources> 

<Grid DataContext="{Binding Source={StaticResource Code}}"> 
    <Grid.RowDefinitions...> 
    <Grid.ColumnDefinitions...> 
    <ComboBox ItemsSource="{Binding Path=Items}" 
       DisplayMemberPath="Name" 
       SelectedValuePath="Id" 
       SelectedIndex="{Binding Path=SelectedIndex}"/> 
    <Button x:Name="butt" Grid.Column="1"    
      Content="{Binding Path=Content}" 
      Command="{Binding Path=MyCommand}"/> 
    <ContentControl Grid.Row="1" Grid.ColumnSpan="2" 
        Content="{Binding Path=MainContent}"/> 
</Grid> 

Beide MainContent1.xaml und MainContent2.xaml enthält nun -

<ContentControl Content="{Binding Path=SubContent}"/> 

Und S1.xaml unter Ordner Sub1 und Sub2 enthält -

<TextBlock Text="{Binding Path=Text}" /> 

Erledigt!