2010-07-01 2 views
1

Я действительно влюбляюсь в целую схему привязки Net. ... но, по-видимому, все еще есть пара исправлений. Предположим, что мой класс имеет переменную-член типа double с именем Susan. Ну, кажется, нет никакого непосредственного способа связать Susan в текстовое поле SusanText потому, что вяжущие выглядит что-то вроде этогоC# привязка переменных класса

SusanText.DataBindings.Add("Text",datasource,"Property")

И Susan не свойство. Поэтому я могу сделать Susan общедоступной собственностью, но этот вид воняет ... что, если я хочу сохранить Susan скрытым? (Я думаю, я мог бы сделать Susan публичным свойством частного экземпляра некоторого внутреннего класса ... но это большая работа для небольшого двойника.) Однако у меня есть большая проблема, поэтому, ради аргумента давайте сделайте следующее:

private double Susan_; 
public double Susan{ get; set;} 
... 
SusanText.DataBindings.Add("Text",this,"Susan") 

Затем все первоначально работает как ожидалось. Если я изменяю SusanText, то изменяется Susan. Однако проблема возникает, когда я напрямую меняю Susan. Я бы хотел, чтобы для SusanText было автоматически обновлено. Поэтому я подозреваю, что мне нужно сделать Susan подкласс double, который реализует какой-то интерфейс IBindable, так что если Susan привязывается к SusanText, то соответствующие события зарегистрированы, а Susan уведомит других, если она будет изменена.

Что является самым простым способом сделать Susan делать то, что я хочу, чтобы она сделала?

Спасибо!

ответ

3

DataBinding ожидает, что класс должен поднять INotifyPropertyChanged, чтобы указать, что значение было изменено и его необходимо перечитать; к сожалению, для реализации этого все еще требуется некоторое ручное кодирование (или что-то вроде PostSharp для IL-переплетения необходимого кода).

Таким образом, для поддержки привязки данных вы не можете использовать автоматически реализованные свойства или привязываться непосредственно к полю - не дает возможности поднять необходимые события (привязка будет работать, но значение не будет обновляется при изменении).

Еще один недостаток DataBinding заключается в том, что он не рассматривает потоки. Если фоновый поток изменяет значение базы данных, тогда привязка данных попытается сделать перекрестный вызов для обновления пользовательского интерфейса - что плохо. Лучшее обходное решение, которое я нашел, - позволить связанным классам содержать экземпляр своего UI's Synchronization Context, который позволит вам обеспечить обновление пользовательского интерфейса в потоке пользовательского интерфейса.

using System.ComponentModel; 

namespace MyWebGrocer.Uma.UI 
{ 
    public class BoundClass : INotifyPropertyChanged 
    { 
    private string _Name; 

    private int _Age; 

    public event PropertyChangedEventHandler PropertyChanged; 

    public string Name 
    { 
     get 
     { 
     return _Name; 
     } 
     set 
     { 
     _Name = value; 
     OnPropertyChanged("Name"); 
     } 
    } 

    public int Age 
    { 
     get 
     { 
     return _Age; 
     } 
     set 
     { 
     _Age = value; 
     OnPropertyChanged("Age"); 
     } 
    } 

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

Я знаю, все это звучит обескураживающим - эти недостатки были привязки данных узнали трудный путь. Однако лучше осознавать - и компенсировать - эти проблемы на ранней стадии, прежде чем они проявятся как большие проблемы.

+0

«вы не можете использовать автоматически реализованы свойства» хорошо, вы можете, вы просто должны стрелять INPC после установки недвижимость. Кажется немного странным, но иногда это полезный шаблон, например, когда вы хотите обновить несколько свойств как часть псевдо транзакции. – Will

+1

@Will, вы можете - но иметь потребительский класс (B) вызывать метод класса databound (A), чтобы (A) поднять событие, пахнет запахом. События в .NET являются специальными делегатами в том, что они только когда-либо предназначены для увольнения из класса - требуя, чтобы внешние компоненты запускали событие, просят людей забыть. ИМО лучше сделать дополнительную работу и сделать класс данных, способный поднимать собственные события. – STW

+0

@stw просто вариант, просто вариант. В любом случае я все использую DependencyObjects. Упростите более связанные свойства, которые у вас есть. – Will

0

Трудно сказать вам самый простой способ, не зная, как ваш код объединяется. Если вы устанавливаете привязки в коде, кажется, что вы все еще делаете что-то трудное.

Вот самый простой способ:

namespace MyProject 
{ 
    public sealed class ViewModel : DependencyObject //handles all databinding voodoo 
    { 
     public string Susan 
     { 
      get { return (string)GetValue(SusanProperty); } 
      set { SetValue(SusanProperty, value); } 
     } 

     public static readonly DependencyProperty 
      SusanProperty = DependencyProperty.Register 
       ("Susan", typeof(string), 
       typeof(ViewModel)); 
    } 
} 

и в XAML:

<Window.DataContext> 
    <ViewModel xmlns="clr-namespace:MyProject" /> 
</Window.DataContext> 
<Grid> 
    <TextBox Text="{Binding Susan}" /> 
</Grid> 
+1

К сожалению, здесь есть немного слишком много вуду для нового, как я. Я еще ничего не знаю о xaml. Кажется, это здорово и полезно, но никто не хочет платить мне, чтобы узнать это прямо сейчас. Спасибо хоть. – JnBrymn

+0

@ Джона честно его не сложно вообще учиться, и, как вы можете видеть, привязка намного проще, чем когда это делается в коде. Кроме того, с усовершенствованиями редактора, такими как данные времени разработки, вы можете использовать окно свойств для создания привязок к реальным типам данных. Вода потрясающая, заходите. – Will

Смежные вопросы