отложенный триггер для расчета с привязкой данных - PullRequest
0 голосов
/ 09 декабря 2018

Я очень новичок в WPF и сейчас изучаю концепции связывания данных.

мой упрощенный код XAML.кроме моей проблемы (ниже) она работает нормально - быстрое и грязное размещение объектов через графический интерфейс, будет убрано после того, как сработает:

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="60"/>
            <RowDefinition/>
            <RowDefinition Height="40"/>
        </Grid.RowDefinitions>
        <Grid Grid.Row="0">
        </Grid>
        <Grid Grid.Row="1">
            <GroupBox Header="Change Type:" Height="95" Width="100" VerticalAlignment="Top" Margin="270,4,422,0" >
                <StackPanel>
                    <RadioButton x:Name="RbtAdd" HorizontalAlignment="Left" Margin="5" VerticalAlignment="Top" GroupName="modGroup" Checked="ModeRadio_Checked">
                        <WrapPanel>
                            <TextBlock Text="Add" Foreground="Green"/>
                        </WrapPanel>
                    </RadioButton>
                    <RadioButton x:Name="RbtPull" HorizontalAlignment="Left" Margin="5" VerticalAlignment="Top" GroupName="modGroup" Checked="ModeRadio_Checked">
                        <WrapPanel>
                            <TextBlock Text="Pull" Foreground="Blue"/>
                        </WrapPanel>
                    </RadioButton>
                    <RadioButton x:Name="RbtModify" HorizontalAlignment="Left" Margin="5" VerticalAlignment="Top" GroupName="modGroup" Checked="ModeRadio_Checked">
                        <WrapPanel>
                            <TextBlock Text="Modify" Foreground="DarkGray"/>
                        </WrapPanel>
                    </RadioButton>
                </StackPanel>
            </GroupBox>

            <TextBlock x:Name="txtCurStock" HorizontalAlignment="Left" Margin="330,181,0,0" TextWrapping="Wrap" Text="{Binding Path=CurrentStock}" VerticalAlignment="Top" FontSize="20" FontWeight="Bold" TextAlignment="Center"/>

            <Label Content="Current stock:" HorizontalAlignment="Left" Margin="289,156,0,0" VerticalAlignment="Top"/>
            <Label x:Name ="lblOperation" Content="Stock to Pull:" HorizontalAlignment="Left" Margin="507,156,0,0" VerticalAlignment="Top"/>
            <TextBox x:Name="txtEntry" HorizontalAlignment="Left" Height="32" Margin="489,181,0,0" TextWrapping="Wrap" TextAlignment="Center" Text="{Binding Path=ModEntry}" VerticalAlignment="Top" Width="120" FontSize="20" FontWeight="Bold" TextChanged="TxtEntry_TextChanged"/>
            <Label Content="New Stock" HorizontalAlignment="Right" Margin="714,156,0,0" VerticalAlignment="Top" Width="68"/>
            <TextBlock Text="{Binding Path=NewStock}" HorizontalAlignment="Right" Margin="0,186,10,0" TextAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" FontSize="20" FontWeight="Bold" Width="68"/>
            <TextBox x:Name="txtComment"  HorizontalAlignment="Left" Height="86" Margin="289,233,0,0" TextWrapping="Wrap" Text="{Binding Path=ModEntry}" VerticalAlignment="Top" Width="493"/>
            <Label Content="Comment:" HorizontalAlignment="Left" Margin="289,207,0,0" VerticalAlignment="Top"/>

            <TextBlock x:Name ="txtModindicator" HorizontalAlignment="Left" Margin="433,181,0,0" TextWrapping="Wrap" Text="-" FontSize="20" FontWeight="Bold" VerticalAlignment="Top"/>
            <TextBlock x:Name ="txtResindicator" HorizontalAlignment="Left" Margin="663,182,0,0" TextWrapping="Wrap" Text="=" FontSize="20" FontWeight="Bold" VerticalAlignment="Top"/>

        </Grid>
    </Grid>

теперь сокращенный код c #:

using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;
using System.Runtime.CompilerServices;


namespace SomeWPF
{
    /// <summary>
    /// Interaction logic for ModifyWindow.xaml
    /// </summary>
    public partial class MainWindow : INotifyPropertyChanged
    {

        public enum Mymode
        {
            add,
            pull,
            modify
        }

        public Mymode mode;

        public MainWindow()
        {
            DataContext = this;
            InitializeComponent();

            CurrentStock = 5;
            RbtPull.IsChecked = true;
            ModEntry = 1;

        }

        private void ModeRadio_Checked(object sender, RoutedEventArgs e)
        {
            if (sender != null)
            {
                if (sender.Equals(RbtAdd))
                {
                    mode = Mymode.add;
                    txtModindicator.Text = "+";
                    txtComment.Text = "Add";
                    lblOperation.Content = "Stock to Add:";
                }
                else if (sender.Equals(RbtPull))
                {
                    mode = Mymode.pull;
                    txtModindicator.Text = "-";
                    txtComment.Text = "Pull";
                    lblOperation.Content = "Stock to Pull:";
                }
                else
                {
                    mode = Mymode.modify;
                    txtModindicator.Text = "~";
                    lblOperation.Content = "Corrected Quantity:";
                    txtComment.Text = "Mod";
                }
                TxtEntry_TextChanged(sender, null);
            }
        }

        private void TxtEntry_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mode == Mymode.add)
            {
                NewStock = CurrentStock + ModEntry;
            }
            else if (mode == Mymode.pull)
            {
                NewStock = CurrentStock - ModEntry;
            }
            else
            {
                NewStock = ModEntry;
            }

        }

        #region Binding Stuff

        private int _newstock;
        public int NewStock
        {

            get
            {

                return _newstock;
            }
            set
            {

                if (_newstock != value)
                {
                    _newstock = value;
                    OnPropertyChanged();
                }
            }
        }

        private int _modentry;
        public int ModEntry
        {
            get
            {
                return _modentry;
            }
            set
            {
                if (_modentry != value)
                {
                    _modentry = value;
                    OnPropertyChanged();
                }
            }
        }

        private int _currentstock;
        public int CurrentStock
        {
            get
            {
                return _currentstock;
            }
            set
            {
                if (_currentstock != value)
                {
                    _currentstock = value;
                    OnPropertyChanged();
                }
            }
        }

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

        #endregion


    }
}

Таким образом, это окно представляет собой всплывающее окно в небольшой программе для хранения инвентаря, чтобы пользователи могли вводить движения инвентаря.до сих пор все нормально, и теперь я хотел сделать довольно простую часть расчета.со «старыми» формами win c # вы бы просто взяли значения и обновили свойство text результата «вручную», но, конечно, мы (I) хотим изучить новые вещи и делать вещи с привязкой данных.Код также выполняет вычисления, но триггер почему-то не тот, что я хочу.

Допустим, текущий запас равен 5 при загрузке окна, режим установлен на Pull (RbtPull) и ввод пользователя (Binding to ModEntry).) устанавливается на 1 с помощью кода.Поэтому NewStock должен иметь значение 4, которое отображается правильно.(yey) Также поле комментария (для отладки на данный момент) отображает значение ModEntry 1. пока все хорошо.

Теперь я ввожу 3 в поле Stock to Pull, но ничего не происходит.(Я хочу, чтобы он реагировал "в реальном времени").Новый Stock по-прежнему отображается как 4, комментарий по-прежнему отображается как 1. Когда я покидаю поле (и щелкаю в поле комментария) - обнаруживается изменение свойства, и поле комментария также показывает 3 (= ModEntry) - так что этоне "в реальном времени", а срабатывает только тогда, когда поле теряет фокус, но это также было бы приемлемо.

Реальная проблема заключается в том, что новый запас остается 4 и не рассчитывается.Теперь, когда я снова вхожу в поле Stock to Pull и изменяю значение, скажем, на 5, поле New Stock обновляется до 2 (то есть до значения, которое я ввел до 5-3 = 2). Перезапись поля снова 5 изменит новоеЗапас до 0. Так что он всегда «на шаг позади».

Из того, что я обнаружил, у меня есть идея, что мне нужен какой-то Binding Converter вместо моего метода вычисления вещей, но я не могудействительно найти что-нибудь подходящее и еще недостаточно знакомы с привязкой данных.Опробовал некоторые вещи уже прямо в коде переменной связывания, но ни одна из них не сработала.Если бы кто-нибудь мог намекнуть мне в правильном направлении, я был бы очень благодарен.(не нужно решение с серебряной пластиной, а просто идея, какой способ поиска (например, если какой-либо тип привязки, который я использую, имеет смысл вообще или есть что-то, что я должен добавить и т.много!

PS: конечно, если кто-то заинтересован в решении проблемы с серебряной тарелкой, я также был бы благодарен. :) - и извините за плохой английский, нет носителя языка.

1 Ответ

0 голосов
/ 10 декабря 2018
Вторая ссылка

@ nosale (см. Комментарии) дала ответ на проблему.Установка обоих полей XAML txtEntry и поля Result в UpdateSourceTrigger = PropertyChanged решила проблему.

, поэтому правильный блок теперь выглядит без изменений в коде c #:

    <Label Content="Current stock:" HorizontalAlignment="Left" Margin="289,156,0,0" VerticalAlignment="Top"/>
    <Label x:Name ="lblOperation" Content="Stock to Pull:" HorizontalAlignment="Left" Margin="507,156,0,0" VerticalAlignment="Top"/>
    <TextBox x:Name="txtEntry" HorizontalAlignment="Left" Height="32" Margin="489,181,0,0" TextWrapping="Wrap" TextAlignment="Center" Text="{Binding Path=ModEntry, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120" FontSize="20" FontWeight="Bold" TextChanged="TxtEntry_TextChanged"/>
    <Label Content="New Stock" HorizontalAlignment="Right" Margin="714,156,0,0" VerticalAlignment="Top" Width="68"/>
    <TextBlock Text="{Binding Path=NewStock, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Right" Margin="0,186,10,0" TextAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" FontSize="20" FontWeight="Bold" Width="68"/>
    <TextBox x:Name="txtComment"  HorizontalAlignment="Left" Height="86" Margin="289,233,0,0" TextWrapping="Wrap" Text="{Binding Path=ModEntry}" VerticalAlignment="Top" Width="493"/>
    <Label Content="Comment:" HorizontalAlignment="Left" Margin="289,207,0,0" VerticalAlignment="Top"/>

Причина:что в текстовых полях по умолчанию UpdateSourceTrigger = LostFocus, а не PropertyChanged, чтобы предотвратить обновления, в которых пользователь вводил опечатки.

что-то новое, чему научились: WPF классен и автоматически обрабатывает недопустимые значения, такие как ноль или строки, и помечает поле красным!:)

еще раз спасибо за ссылки!

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