Пользовательский элемент управления DependencyProperties не обновляется, поскольку они являются ссылками - PullRequest
0 голосов
/ 04 ноября 2019

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

Мы используем Prism, и у нас естьViewModel и View для отображения и редактирования свойств устройства. Эти свойства читаются из XML при запуске и добавляются в устройство как словарь настроек. И Настройки, и Устройство реализуют INotifyPropertyChanged, и когда значение Настройки изменяется, Устройство также вызывает событие Изменено свойство для этого Настройки.

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

enter image description here

Если я изменю значение в пользовательском элементе управления, оно будет обновлено и в другом. Привязка к источнику в порядке:

enter image description here

Но если я изменю его на другой, он не будет обновлен в пользовательском элементе управления. Привязка из источника не в порядке:

enter image description here

Также, если я изменяю значение условия str_pressureUnit, преобразование выполняется только в старом коде. Привязка условия преобразования не в порядке:

enter image description here

Но элемент управления «Включить / отключить» работает правильно для обоих. Включите ok:

enter image description here

Простые примеры с другим пользовательским элементом управления и свойствами из устройства, которые не являются динамическими, работают нормально, если я использую `Mode =" TwoWay». Я думал, что, возможно, это проблема с Multibindings или с конфигурацией Dynamic Settings, но поскольку работает с EnableProperties (что является обычным свойством ViewModel), я подозреваю, что это может быть что-то, связанное со свойствами Dynamic.

Вот так выглядит наш класс Device:

  public class Device : DynamicObject, INotifyPropertyChanged
  {
            #region Properties

            ...
            public Dictionary<string, ISetting> DynamicSettings { get; private set; } = new Dictionary<string, ISetting>(); 
            ...
            public Device(SettingDefinitionsProvider settingDefinitionsProvider, ICommunicationChannel communicationChannel, DeviceType deviceType)
            {
                ...
                foreach(ISetting s in DynamicSettings.Values)
                {
                    s.PropertyChanged += OnSettingValueUpdated;
                }

            }
        ...
        #region INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName]string propertyname = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
        }

        #endregion //INotifyPropertyChanged

        #region EventHandlers

        private void OnSettingValueUpdated(object sender, PropertyChangedEventArgs e)
        {
            if(sender is ISetting)
            {
                OnPropertyChanged((sender as ISetting).Name);
            }
        }

        #endregion //EventHandlers
  }

И класс Setting генерирует событие PropertyChanged при изменении его значения.

ViewModel имеет свойство SelectedDevice ион установлен как DataContext представления с функциональностью AutoWireViewModel Prism.

Мы также используем MultiBinding и некоторые сложные конвертеры, потому что некоторые отображаемые значения параметров могут изменяться в зависимости от другого значения параметра, а также от включенного элемента управления и т. д. Таким образом, одна запись в XAML для параметра может получить такой большой размер:

<TextBlock Grid.Row="4" Text="{Binding SelectedDevice.SafetyMargin.DisplayName}" Margin="5"/>
    <TextBox Grid.Row="4" Grid.Column="1"  Margin="5">
        <TextBox.IsEnabled>
            <MultiBinding Converter="{conv:EnableControlConverter}">
                <Binding RelativeSource="{RelativeSource AncestorType={x:Type UserControl}, Mode=FindAncestor}" Path="DataContext.SelectedDevice.SafetyMargin"/>
                <Binding RelativeSource="{RelativeSource AncestorType={x:Type UserControl}, Mode=FindAncestor}" Path="DataContext.EnableControls"/>
            </MultiBinding>
        </TextBox.IsEnabled>
        <MultiBinding Converter="{conv:ConversionConverter}">
            <Binding RelativeSource="{RelativeSource AncestorType={x:Type UserControl}, Mode=FindAncestor}" Path="DataContext.SelectedDevice.SafetyMargin"/>
            <Binding RelativeSource="{RelativeSource AncestorType={x:Type UserControl}, Mode=FindAncestor}" Path="DataContext.SelectedDevice.PressureUnit"/>
        </MultiBinding>
    </TextBox>
    <TextBlock Grid.Row="4" Grid.Column="2"  Margin="5">
        <TextBlock.Text>
            <MultiBinding Converter="{conv:UnitLabelConverter}">
                <Binding RelativeSource="{RelativeSource AncestorType={x:Type UserControl}, Mode=FindAncestor}" Path="DataContext.SelectedDevice.SafetyMargin"/>
                <Binding RelativeSource="{RelativeSource AncestorType={x:Type UserControl}, Mode=FindAncestor}" Path="DataContext.SelectedDevice.PressureUnit"/>
            </MultiBinding>
        </TextBlock.Text>
    </TextBlock>

Чтобы упростить добавление новых параметров (это является причиной чтения из xml и т. Д.), Я создал новыйПользовательский контроль. Его XAML:

<UserControl ...
         x:Name="parent">

<Grid DataContext="{Binding ElementName=parent}">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>

    <TextBlock Text="{Binding Path=Setting.DisplayName}" Margin="5"/>
    <TextBox Grid.Column="1"  Margin="5">
        <TextBox.IsEnabled>
            <MultiBinding Converter="{conv:EnableControlConverter}">
                <Binding Path="Setting"/>
                <Binding Path="Enabled"/>
            </MultiBinding>
        </TextBox.IsEnabled>
        <MultiBinding Mode="TwoWay" Converter="{conv:ConversionConverter}">
            <Binding Path="Setting"/>
            <Binding Path="ConditionSetting"/>
        </MultiBinding>
    </TextBox>
    <TextBlock Grid.Column="2"  Margin="5">
        <TextBlock.Text>
            <MultiBinding Converter="{conv:UnitLabelConverter}">
                <Binding Path="Setting"/>
                <Binding Path="ConditionSetting"/>
            </MultiBinding>
        </TextBlock.Text>
    </TextBlock>
</Grid>

И код позади:

public partial class CustomTextBox : UserControl
{
    protected static Logger logger = LogManager.GetCurrentClassLogger();

    public static readonly DependencyProperty SettingProperty =
        DependencyProperty.Register("Setting", typeof(object),
          typeof(CustomTextBox), new PropertyMetadata(""));

    public static readonly DependencyProperty ConditionSettingProperty =
        DependencyProperty.Register("ConditionSetting", typeof(object),
          typeof(CustomTextBox), new PropertyMetadata(""));

    public static readonly DependencyProperty EnabledProperty =
        DependencyProperty.Register("Enabled", typeof(object),
          typeof(CustomTextBox), new PropertyMetadata(""));

    public object Setting
    {
        get { return (object)GetValue(SettingProperty); }
        set { SetValue(SettingProperty, value); }
    }

    public object ConditionSetting
    {
        get { return (object)GetValue(ConditionSettingProperty); }
        set { SetValue(ConditionSettingProperty, value); }
    }

    public object Enabled
    {
        get { return (object)GetValue(EnabledProperty); }
        set { SetValue(EnabledProperty, value); }
    }

    public CustomTextBox()
    {
        InitializeComponent();
    }

}

И это новый код в представлении:

<controls:CustomTextBox Grid.Row="3" 
    Setting="{Binding SelectedDevice.SafetyMargin, Mode=TwoWay}" 
    ConditionSetting="{Binding SelectedDevice.PressureUnit, Mode=TwoWay}" 
    Enabled="{Binding EnableControls}"/>

Любой совет будет высоко оценен, заранее спасибо.

1 Ответ

0 голосов
/ 05 ноября 2019

Вы отладили?

  • В обоих случаях вызывается обратный вызов OnSettingValueUpdated в вашем классе устройств и есть ли различия?

  • Установлены ли в вашем UserControl установщики ConditionSetting / Setting?

Я бы сказал, что как-то PropertyChanged не выполняется должным образом или не достигает свойства ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...