O co chodzi z <Window.DataContext>

0

Nie rozumiem takiego kodu źródłowego z <Window.DataContext>:

<Window x:Class="Hierarchy.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Hierarchy"
        mc:Ignorable="d"
        Title="MainWindow" Height="453.583" Width="525">
    <Window.DataContext>
        <local:ViewModel/>
    </Window.DataContext>
...
</Window>

Chodzi o to, że główny form ma zapięty ViewModel i ja się pytam po co? Teraz nie mogę stworzyć przycisku, który np dodaje coś do m_folders.

Kod tego ViewModelu poniżej:


namespace Hierarchy
{
    class ViewModel : INotifyPropertyChanged
    {
        public ViewModel()
        {
            TEST = "jubba";

            m_folders = new List<IFolder>();

            //add Root items
            Folders.Add(new Folder { FolderLabel = "Dummy1", FullPath = @"C:\dummy1" });
            Folders.Add(new Folder { FolderLabel = "Dummy2", FullPath = @"C:\dummy2" });
            Folders.Add(new Folder { FolderLabel = "Dummy3", FullPath = @"C:\dummy3" });
            Folders.Add(new Folder { FolderLabel = "Dummy4", FullPath = @"C:\dummy4" });

            //add sub items
            Folders[0].Folders.Add(new Folder { FolderLabel = "Dummy11", FullPath = @"C:\dummy11" });
            Folders[0].Folders.Add(new Folder { FolderLabel = "Dummy12", FullPath = @"C:\dummy12" });
            Folders[0].Folders.Add(new Folder { FolderLabel = "Dummy13", FullPath = @"C:\dummy13" });
            Folders[0].Folders.Add(new Folder { FolderLabel = "Dummy14", FullPath = @"C:\dummy14" });


            Folders[0].Folders.Add(new Folder { FolderLabel = "Dummy24", FullPath = @"C:\dummy14" });


            Folders[0].Folders[0].Folders.Add(new Folder { FolderLabel = "xxxxx", FullPath = @"C:\dummy14" });
            Folders[0].Folders[0].Folders.Add(new Folder { FolderLabel = "vcxvx", FullPath = @"C:\dummy14" });
            Folders[0].Folders[0].Folders.Add(new Folder { FolderLabel = "vvxcvxcvcx", FullPath = @"C:\dummy14" });

        }
        

        public string TEST { get; set; }


        private List<IFolder> m_folders;
        public List<IFolder> Folders
        {
            get { return m_folders; }
            set
            {
                m_folders = value;
                NotifiyPropertyChanged("Folders");
            }
        }

        void NotifiyPropertyChanged(string property)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(property));
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}

Kod pochodzi z tego przykładu:

http://blog.clauskonrad.net/2011/04/how-to-make-hierarchical-treeview.html

0

Dlaczego nie możesz? Przecież od tego jest w buttonie Command a w ViewModelu za to odpowiada interfejs ICommand. Zaimplementuj sobie ICommand i przez niego wywołuj buttony.

A DataContext oznacza tyle, że wskazana klasa jest kontekstem danej kontrolki. To jest takie połączenie widoku (View) z jego modelem (ViewModel).

0
UnlimitedPL napisał(a):

Dlaczego nie możesz? Przecież od tego jest w buttonie Command a w ViewModelu za to odpowiada interjest ICommand. Zaimplementuj sobie ICommand i przez niego wywołuj buttony.

A DataContext oznacza tyle, że wskazana klasa jest kontekstem danej kontrolki. To jest takie połączenie widoku (View) z jego modelem (ViewModel).

Zarzuć przykładowym kodem jak to połączyć

0

Nie warto robić z gotowego rozwiązania.
Implementujesz sobie interfejs ICommand

public class ActionCommand : ICommand
    {
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        private Action methodToExecute;
        private Func<bool> canExecuteEvaluator;

        public ActionCommand(Action methodToExecute, Func<bool> canExecuteEvaluator)
        {
            this.methodToExecute = methodToExecute;
            this.canExecuteEvaluator = canExecuteEvaluator;
        }

        public ActionCommand(Action methodToExecute)
            : this(methodToExecute, null)
        {
        }

        public bool CanExecute(object parameter)
        {
            if (canExecuteEvaluator == null)
            {
                return true;
            }
            else
            {
                bool result = canExecuteEvaluator.Invoke();
                return result;
            }
        }

        public void Execute(object parameter)
        {
            methodToExecute.Invoke();
        }
    }

następnie robisz buttona
<Button Command="{Binding AddFolderCommand}" />

następnie w ViewModelu dodajesz gdzieś:

public ICommand AddFolderCommand { get; set; }

// gdzies np w konstruktorze
AddFolderCommand = new ActionCommand(AddFolder);
//

private void AddFolder()
{
... //tutaj Twój kod po naciśnięciu buttona
}

oprócz ActionCommand pisane z palca więc jak gdzieś wkradła się literówka to musisz poprawić

0
UnlimitedPL napisał(a):

Nie warto robić z gotowego rozwiązania.
Implementujesz sobie interfejs ICommand

public class ActionCommand : ICommand
    {
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        private Action methodToExecute;
        private Func<bool> canExecuteEvaluator;

        public ActionCommand(Action methodToExecute, Func<bool> canExecuteEvaluator)
        {
            this.methodToExecute = methodToExecute;
            this.canExecuteEvaluator = canExecuteEvaluator;
        }

        public ActionCommand(Action methodToExecute)
            : this(methodToExecute, null)
        {
        }

        public bool CanExecute(object parameter)
        {
            if (canExecuteEvaluator == null)
            {
                return true;
            }
            else
            {
                bool result = canExecuteEvaluator.Invoke();
                return result;
            }
        }

        public void Execute(object parameter)
        {
            methodToExecute.Invoke();
        }
    }

ok ale nie rozumiem gdzie wstawic powyzsze? mozesz jasniej?

1

stwórz sobie nie wiem nowy plik .cs i sobie wklej tą klasę. i już raz napisaną taką klasę używaj w każdym ViewModelu.

0
UnlimitedPL napisał(a):

stwórz sobie nie wiem nowy plik .cs i sobie wklej tą klasę. i już raz napisaną taką klasę używaj w każdym ViewModelu.

Ok dzięki. Sama ta kombinacja działa. Czy ta kombinacja to idea MVVM? Z którą nigdy nie miałam styczności.

Może wiesz również dlaczego nie działa esencjonalny problem, czyli po dodaniu nowego folderka, drzewko mi się nie odświeża?

private void AddFolder()
        {
            MessageBox.Show(Folders.Count.ToString());
            Folders.Add(new Folder { FolderLabel = "fdsafsdfsd", FullPath = @"C:\dummy1333" });
            MessageBox.Show(Folders.Count.ToString());

        }

Dodaje takim kodem, więc na bank jest fizycznie dodawany do listy folderów.

1

Bo kolekcję masz typu List. Zrób ją typu ObservableCollection lub wywołuj PropertyChanged dla swojej kolekcji Folders.

Tą klasę ActionCommand można napisać w taki sposób że będzie dawała masę większych możliwości. To jest podany przykład. Rozbudowywać możesz sobie ją sam.

0

Ok, chodzi a potrafisz mi udzielić odpowiedzi czy to jest MVVM?

Druga sprawa dlaczego nie mogę kliknąć, zaznaczyć żadnego Itema na TreeView?

0

Tylko ja nie mam żadnego stylu, bo kod taki:

<Window x:Class="Hierarchy.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Hierarchy"
        mc:Ignorable="d"
        Title="MainWindow" Height="453.583" Width="525">
    <Window.DataContext>
        <local:ViewModel/>
    </Window.DataContext>
    <Grid>
        <StackPanel>
            <!-- simple root level binding-->
            <TextBlock Text="Simple root binding}"/>
            <TreeView ItemsSource="{Binding Folders}" >
                <TreeView.ItemTemplate>
                    <DataTemplate>
                        <TreeViewItem Header="{Binding FolderLabel}"/>
                    </DataTemplate>
                </TreeView.ItemTemplate>
            </TreeView>

            <!-- hieracical binding -->
            <TextBlock Text="Hierarchical root binding}"/>
            <TreeView ItemsSource="{Binding Folders}" Height="200">

               
                <TreeView.ItemTemplate>

                    

                    <HierarchicalDataTemplate ItemsSource="{Binding Folders}" DataType="{x:Type local:IFolder}">
                        <TreeViewItem Header="{Binding FolderLabel}"/>
                    </HierarchicalDataTemplate>

                    

                </TreeView.ItemTemplate>
            </TreeView>
            <Button x:Name="button" Content="Button" Command="{Binding AddFolderCommand}"/>
            <Button x:Name="button1" Content="Button" />

        </StackPanel>
    </Grid>
</Window>

I jest BRZYDKO! :(

A tu jest ładnie i też kod ma taki sam wygląd, czyli brak wyglądu:

<Window x:Class="WpfApplicationTreeView.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplicationTreeView"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TreeView x:Name="treeView" HorizontalAlignment="Left" Height="257" Margin="24,26,0,0" VerticalAlignment="Top" Width="297">
            <TreeViewItem Header="dsadsa"/>
            <TreeViewItem Header="dasdsadsa"/>
            <TreeViewItem Header="bvcbvcbcv"/>
        </TreeView>

    </Grid>
</Window>

wyglad.png

Na powyższym obrazku. Pierwsze jest normalne. Drugie rozwalone. Gdzie może być przyczyna powyższego błędu??

0

Czego oczekujesz? Podałem informacje które są potrzebne. W takim wypadku definiujesz ItemTemplate TreeViewItem'a.
Pisane z palca może nie działać:

...
<HierarchicalDataTemplate ItemsSource="{Binding Folders}">
                        <TreeViewItem>
                            <TreeViewItem.ItemTemplate>
                                <DataTemplate>
                                    <Label Content="{Binding FolderLabel}"
                                           Margin="0 0 0 0" />
                                </DataTemplate>
                            </TreeViewItem.ItemTemplate>
                        </TreeViewItem>
                    </HierarchicalDataTemplate>
...

pozycją tekstu sterujesz Margin'em Label'a. Zera znaczą analogicznie LEFT TOP RIGHT BOTTOM. Przejdź jakiś kurs XAML'a

0
UnlimitedPL napisał(a):

Czego oczekujesz? Podałem informacje które są potrzebne. W takim wypadku definiujesz ItemTemplate TreeViewItem'a.
Pisane z palca może nie działać:
...
<HierarchicalDataTemplate ItemsSource="{Binding Folders}">
<TreeViewItem>
<TreeViewItem.ItemTemplate>
<DataTemplate>
<Label Content="{Binding FolderLabel}"
Margin="0 0 0 0" />
</DataTemplate>
</TreeViewItem.ItemTemplate>
</TreeViewItem>
</HierarchicalDataTemplate>
...

> pozycją tekstu sterujesz Margin'em Label'a. Zera znaczą analogicznie LEFT TOP RIGHT BOTTOM. Przejdź jakiś kurs XAML'a


Ok wygląda coś tam lepiej. Czy ten template oznacza, że teraz dziaciami są elementy typu Label a przedtem były to TreeViewItem-y?

1 użytkowników online, w tym zalogowanych: 0, gości: 1