Почему мой пользовательский интерфейс не будет обновляться и привязываться к данным, когда я устанавливаю DataContext для объекта - PullRequest
0 голосов
/ 16 мая 2018

Так что в этот момент я очень смущен. То, как я это связал в данный момент, работает просто отлично, но я бы хотел привязать данные, используя несколько классов. Итак, что у меня есть сейчас (рабочая версия), это ... В моем MainWindow я настроил DataContext для нового экземпляра моего класса с именем Server

public MainWindow()
{
    InitializeComponent();
    DataContext = server;
}

И я связал несколько свойств с парой элементов управления, например:

<ScrollViewer VerticalScrollBarVisibility="Visible" Name="Scroller" Margin="266,95,10,192" Background="#1f1f1f">
    <StackPanel>
    <ItemsControl ItemsSource="{Binding ConsoleOutput, Mode=OneWay}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                <TextBlock Text="{Binding Text}"
                               Foreground="{Binding Foreground}"
                               Name="SavedBlocks" FontFamily="Consolas"
                               LayoutUpdated="SavedBlocks_LayoutUpdated" />
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </StackPanel>
</ScrollViewer>

И это прямо здесь, мой Server класс

public class Server : INotifyPropertyChanged
{
    public string consoleInput = string.Empty;
    public ObservableCollection<Message> consoleOutput = new ObservableCollection<Message>();

    public Server()
    {

    }

    public string ConsoleInput
    {
        get => consoleInput;
        set
        {
            consoleInput = value;
            OnPropertyChanged("ConsoleInput");
        }
    }


private void OKDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (ServerIsRunning)
            {
                if (!string.IsNullOrEmpty(e.Data))

                    Application.Current.Dispatcher.Invoke(() =>
                    {
                        if (e.Data.Contains("ERROR"))
                        {
                            ConsoleOutput.Add(new Message { Text = e.Data, Foreground = ERRORBrush });
                            ConsoleInput = string.Empty;
                            return;
                        }

                        if (e.Data.Contains("WARN"))
                        {
                            ConsoleOutput.Add(new Message { Text = e.Data, Foreground = WARNINGBrush });
                            ConsoleInput = string.Empty;
                            return;
                        }

                        ConsoleOutput.Add(new Message { Text = e.Data, Foreground = OKBrush });
                        ConsoleInput = string.Empty;
                    });
            }
        }


    public ObservableCollection<Message> ConsoleOutput
    {
        get => consoleOutput;
        set
        {
            consoleOutput = value;
            OnPropertyChanged("ConsoleOutput");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        if (null != PropertyChanged)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

И, как вы можете видеть, у ObservableCollection есть тип Message, которым был бы этот класс

public class Message : INotifyPropertyChanged
{
    public Message()
    {
        _foreground = Brushes.Green;
    }
    private string _text;
    public string Text
    {
        get { return _text; }
        set { _text = value; OnPropertyChanged("Text"); }
    }

    private Brush _foreground;
    public Brush Foreground
    {
        get { return _foreground; }
        set
        {
            _foreground = value;
            OnPropertyChanged("Foreground");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    void OnPropertyChanged(string propertyName)
    {
        if (null != PropertyChanged)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

И проблема, с которой я столкнулся, заключалась в том, что я пытался создать класс MasterViewModel, который бы содержал свойства всех других классов, например

public class MasterViewModel
{
    public Server ServerViewModel { get; } = new Server();
    public Player PlayerViewModel { get; } = new Player();
    public Message MessageViewModel { get; } = new Message();
}

А потом я собирался установить свойства следующим образом

а также изменение DataContext

public MainWindow()
{
    InitializeComponent();
    DataContext = new MasterViewModel();
}

1024 * XAML *

<ItemsControl ItemsSource="{Binding ServerViewModel.ConsoleOutput, Mode=OneWay}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
        <TextBlock Text="{Binding MessageViewModel.Text}"
                       Foreground="{Binding MessageViewModel.Foreground}"
                       Name="SavedBlocks" FontFamily="Consolas"
                       LayoutUpdated="SavedBlocks_LayoutUpdated" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Но затем внезапно, когда он перестал работать, он не уведомлял пользовательский интерфейс, а пользовательский интерфейс вообще не обновлялся. Я что-то здесь упускаю? Потому что я не могу ради своей жизни найти проблему здесь.

НОВАЯ СВЯЗЬ

static Server server = new Server();
        static Player player = new Player();
        static Message message = new Message();

        public MainWindow()
        {
            InitializeComponent();
            DataContext = new MasterViewModel()
            {
                ServerViewModel = server,
                PlayerViewModel = player,
                MessageViewModel = message,
            };
        }

Ответы [ 3 ]

0 голосов
/ 16 мая 2018

Вам необходимо установить свойство ServerViewModel класса MasterViewModel для объекта server, который у вас был ранее:

public MainWindow()
{
    InitializeComponent();
    DataContext = new MasterViewModel() { ServerViewModel = server };
}

Это означает, что вы должны добавить установщики к свойствам MasterViewModel:

public class MasterViewModel
{
    public Server ServerViewModel { get; set; }
    public Player PlayerViewModel { get; set; }
    public Message MessageViewModel { get; set; }
}

Обязательно установите также свойства PlayerViewModel и Message.

0 голосов
/ 17 мая 2018

Итак, вот что я сделал с небольшим образцом

public class MasterVM 
    {
        public ServerVM Server { get; set; }
    }

    public class ServerVM : INotifyPropertyChanged

    {
        private string serverName;
        public string ServerName {
            get
            {
                return serverName;
            }
            set
            {
                serverName = value;
                OnPropertyChanged("ServerName");        
            }

        }

        private void OnPropertyChanged(string name)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }

А вот xaml

<Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Button Click="Button_Click">Change Server NAme</Button>

        <Label Grid.Row="1" Content="{Binding Server.ServerName}" />

    </Grid>

, и он работает как шарм.

ЧтоЯ могу предложить вам сделать, чтобы в каждом классе было поле _id, инициализироваться новым GUID и использовать инструмент под названием «Snoop» для проверки идентификатора времени выполнения этих объектов.

0 голосов
/ 16 мая 2018

вы не должны были изменять привязки внутри ItemTemplate. ObservableCollection<Message> ConsoleOutput по-прежнему содержит объекты сообщений со свойствами текста и переднего плана. Путь привязки MessageViewModel.Text недопустим для сообщения, вернитесь к {Binding Text} и {Binding Foreground}

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