Binding objects defined in code-behind

前端 未结 11 1265
难免孤独
难免孤独 2020-11-28 04:29

I have some object that is instantiated in code behind, for instance, the XAML is called window.xaml and within the window.xaml.cs

protected Dictionary

        
相关标签:
11条回答
  • 2020-11-28 04:44

    That's my way to bind to code behind (see property DataTemplateSelector)

    public partial class MainWindow : Window
    {
      public MainWindow()
      {
        this.DataTemplateSelector = new MyDataTemplateSelector();
    
        InitializeComponent();
    
        // ... more initializations ...
      }
    
      public DataTemplateSelector DataTemplateSelector { get; }
    
      // ... more code stuff ...
    }
    

    In XAML will referenced by RelativeSource via Ancestors up to containing Window, so I'm at my Window class and use the property via Path declaration:

    <GridViewColumn Header="Value(s)"
                    CellTemplateSelector="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataTemplateSelector}"/>
    
    

    Setting of property DataTemplateSelector before call InitializeComponent depends on missing implementation of IPropertyChanged or use of implementation with DependencyProperty so no communication run on change of property DataTemplateSelector.

    0 讨论(0)
  • 2020-11-28 04:45

    While Guy's answer is correct (and probably fits 9 out of 10 cases), it's worth noting that if you are attempting to do this from a control that already has its DataContext set further up the stack, you'll resetting this when you set DataContext back to itself:

    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    

    This will of course then break your existing bindings.

    If this is the case, you should set the RelativeSource on the control you are trying to bind, rather than its parent.

    i.e. for binding to a UserControl's properties:

    Binding Path=PropertyName, 
            RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}
    

    Given how difficult it can be currently to see what's going on with data binding, it's worth bearing this in mind even if you find that setting RelativeSource={RelativeSource Self} currently works :)

    0 讨论(0)
  • 2020-11-28 04:46

    In your code behind, set the window's DataContext to the dictionary. In your XAML, you can write:

    <ListView ItemsSource="{Binding}" />
    

    This will bind the ListView to the dictionary.

    For more complex scenarios, this would be a subset of techniques behind the MVVM pattern.

    0 讨论(0)
  • 2020-11-28 04:55

    Define a converter:

    public class RowIndexConverter : IValueConverter
    {
        public object Convert( object value, Type targetType,
                               object parameter, CultureInfo culture )
        {
            var row = (IDictionary<string, object>) value;
            var key = (string) parameter;
            return row.Keys.Contains( key ) ? row[ key ] : null;
        }
    
        public object ConvertBack( object value, Type targetType,
                                   object parameter, CultureInfo culture )
        {
            throw new NotImplementedException( );
        }
    }
    

    Bind to a custom definition of a Dictionary. There's lot of overrides that I've omitted, but the indexer is the important one, because it emits the property changed event when the value is changed. This is required for source to target binding.

    public class BindableRow : INotifyPropertyChanged, IDictionary<string, object>
    {
        private Dictionary<string, object> _data = new Dictionary<string, object>( );
    
        public object Dummy   // Provides a dummy property for the column to bind to
        {
            get
            {
                return this;
            }
            set
            {
                var o = value;
            }
        }
    
    
        public object this[ string index ]
        {
            get
            {
                return _data[ index ];
            }
            set
            {
                _data[ index ] = value;
                InvokePropertyChanged( new PropertyChangedEventArgs( "Dummy" ) ); // Trigger update
            }
        }
    
    
    }
    

    In your .xaml file use this converter. First reference it:

    <UserControl.Resources>
        <ViewModelHelpers:RowIndexConverter x:Key="RowIndexConverter"/>
    </UserControl.Resources>
    

    Then, for instance, if your dictionary has an entry where the key is "Name", then to bind to it: use

    <TextBlock  Text="{Binding Dummy, Converter={StaticResource RowIndexConverter}, ConverterParameter=Name}">
    
    0 讨论(0)
  • 2020-11-28 04:55

    I was having this exact same problem but mine wasn't because I was setting a local variable... I was in a child window, and I needed to set a relative DataContext which I just added to the Window XAML.

    <Window x:Class="Log4Net_Viewer.LogItemWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        Title="LogItemWindow" Height="397" Width="572">
    
    0 讨论(0)
提交回复
热议问题