Трудности с привязкой данных - PullRequest
0 голосов
/ 19 мая 2019

Привязка данных - сложная концепция, которую я до сих пор не могу понять, несмотря на то, что уже прочитал десятки тем.

Я хочу иметь TextBox, который бы изменял свой текст каждый раз, когда поле «status» изменяется в моем коде, для целей отладки.

Вот что у меня есть:

public partial class ReviewsControl : UserControl
{
    private Status status = MainControl.AppStatus;
    public string StatusDisplay
    {
        get
        {
            return status.ToString();
        }
    }
}

А вот мое мнение:

<TextBlock x:Name="StatusBlock" HorizontalAlignment="Left" Margin="10,450,0,0" TextWrapping="Wrap" Text="{Binding StatusDisplay, Source=ReviewsControl, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Height="40" Width="205"/>

Код выше даже ничего не показывает, не говоря уже о том, чтобы делать это динамически. Что я должен изменить, если я хочу, чтобы XAML обнаружил изменения в моем коде C # и соответственно изменил текстовое поле?

Ответы [ 2 ]

2 голосов
/ 19 мая 2019

У меня тоже были проблемы на ранней стадии. Ваше представление (отображение конечным пользователям) не заботится о том, как и откуда что-то происходит, вы просто знаете, что будет отображаться в вашем контроллере View Model для привязки. Чтобы обновлять информацию в вашем представлении, наиболее распространенным является связывание, и ваша модель представления включает в себя интерфейс INotifyPropertyChanged. Это делается для того, чтобы вы могли принудительно вызвать событие при изменении свойства, что бы оно ни «слушало», оно само обновится ..

Простой класс, вы можете просто получить из: INotify, событие, которое доступно для регистрации вещей, и ваш метод, чтобы фактически ПОДНИМАТЬ событие, чтобы передать поток для тех, кто слушает изменения.

public class SomeBaseClass : INotifyPropertyChanged
{
   public event PropertyChangedEventHandler PropertyChanged;
   public void RaisePropertyChanged(string propertyName)
   {
      if (PropertyChanged != null)
         PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
   }
}

Как только это будет сделано, вы будете открывать свойства в своем классе, делая их общедоступными с помощью getter / setters. Вы не привязываетесь к полю.

public string SomeThingYouWantToExpose {get; set; }

И в вашем коде, как бы вы ни получали данные, обновляли метки, что угодно, вы бы устанавливали и поднимали измененное свойство

public void GettingSomeData()
{
   // … doing something to get / prepare / whatever...
   SomeThingYouWantToExpose = "some new label";
   // Now raise which the view bound to this property will updated itself
   RaisePropertyChanged( "SomeThingYouWantToExpose" );
}

Теперь, по вашему мнению, вы должны привязаться к любому объекту модели представления, а затем к свойству класса. Не знаю, нужна ли вам ссылка x: Name, что делает это поле вашим контролем. В этом примере нет необходимости, если только вы не пытаетесь привязать другие элементы управления на одном экране в результате этого поля.

<TextBlock Height="40" Width="205"  Margin="10,450,0,0"
   HorizontalAlignment="Left" VerticalAlignment="Top" 
   DataContext="{Binding YourViewModelObjectName}"
   Text="{Binding SomeThingYouWantToExpose}" 
   TextWrapping="Wrap" />

Надеюсь, эти фрагменты в вашем сценарии будут иметь смысл и продвинут вас вперед в вашем проекте. Любые дополнительные разъяснения, дайте мне знать.

УТОЧНЕНИЕ О СВЯЗАНИИ КОНТЕКСТА ДАННЫХ

Как я реализовал в своих приложениях, у меня будет

MyView -- via the visual declaration... be it a window, grid, complex user control with many controls, whatever...


MyDataModel - a class that is used to query data from whatever data source, such as SQL-Server.


MyView_ViewModel - a custom class that has the INotifyPropertyChanged incorporated and where I expose different properties and other objects I want to expose / make available to the view

Итак, в MyData_ViewModel я создал бы представление, а также создал бы свою модель представления. После создания представления я бы установил для DataContext общего вида значение «MyView_ViewModel»

public class MyData_ViewModel : INotifyPropertyChanged
{
   public event PropertyChangedEventHandler PropertyChanged;
   public void RaisePropertyChanged(string propertyName)
   {
      if (PropertyChanged != null)
         PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
   }

   public void LoadingMyDataAndView()
   {
      // Controller I use to get whatever data I need from ex: SQL
      _myDataModel = new MyDataModel();

      // the view / window / control I want to present to users
      _myView = new MyView();

      // Now, set the data context on the view to THIS ENTIRE OBJECT.
      // Now, anything on THIS class made as public can be have a binding
      // directly to the control in the view.  Since the DataContext is 
      // set here, I can bind to anything at this level or lower that is public.
      _myView.DataContext = this;
   }

   private MyView _myView;
   private MyDataModel _myDataModel;

   // such as example exposed property
   public string SomeThingYouWantToExpose {get; set; }

   public void GettingSomeData()
   {
      var something = _myDataModel.GetSomeData();

      // … doing something to get / prepare / whatever...
      SomeThingYouWantToExpose = "some new label";
      // Now raise which the view bound to this property will updated itself
      RaisePropertyChanged( "SomeThingYouWantToExpose" );
   }
}

Надеюсь, этот ПРИМЕР показывает, как части соединяются вместе. Представлению больше не потребуется отдельный набор DataContext, поскольку задано все представление, просто необходимо привязать его к отдельному общедоступному свойству.

1 голос
/ 19 мая 2019

Предполагая, что TextBlock является дочерним элементом UserControl, т.е. что

<TextBlock x:Name="StatusBlock" Text="{Binding StatusDisplay}" ... />

объявлено в XAML UserControl, RelativeSource привязки должен быть установлен в родительский UserControl следующим образом:

<TextBlock Text="{Binding StatusDisplay,
                  RelativeSource={RelativeSource AncestorType=UserControl}}" />

Поскольку StatusDisplay является свойством UserControl, то есть DependencyObject, его следует объявить как свойство зависимости:

public partial class ReviewsControl : UserControl
{
    public static readonly DependencyProperty StatusDisplayProperty =
        DependencyProperty.Register(
            nameof(StatusDisplay), typeof(string), typeof(ReviewsControl);

    public string StatusDisplay
    {
        get { return (string)GetValue(StatusDisplayProperty); }
        set { SetValue(StatusDisplayProperty, value); }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...