O co chodzi z <Window.DataContext>

O co chodzi z <Window.DataContext>
QU
  • Rejestracja:ponad 9 lat
  • Ostatnio:prawie 9 lat
  • Postów:65
0

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

Kopiuj
<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:

Kopiuj

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

UnlimitedPL
  • Rejestracja:prawie 12 lat
  • Ostatnio:ponad 6 lat
  • Postów:231
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).

edytowany 2x, ostatnio: UnlimitedPL
QU
  • Rejestracja:ponad 9 lat
  • Ostatnio:prawie 9 lat
  • Postów:65
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ć

UnlimitedPL
  • Rejestracja:prawie 12 lat
  • Ostatnio:ponad 6 lat
  • Postów:231
0

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

Kopiuj
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ś:

Kopiuj
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ć

edytowany 4x, ostatnio: UnlimitedPL
QU
  • Rejestracja:ponad 9 lat
  • Ostatnio:prawie 9 lat
  • Postów:65
0
UnlimitedPL napisał(a):

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

Kopiuj
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?

UnlimitedPL
  • Rejestracja:prawie 12 lat
  • Ostatnio:ponad 6 lat
  • Postów:231
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.

edytowany 1x, ostatnio: UnlimitedPL
QU
  • Rejestracja:ponad 9 lat
  • Ostatnio:prawie 9 lat
  • Postów:65
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?

Kopiuj
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.

UnlimitedPL
  • Rejestracja:prawie 12 lat
  • Ostatnio:ponad 6 lat
  • Postów:231
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.

edytowany 3x, ostatnio: UnlimitedPL
QU
  • Rejestracja:ponad 9 lat
  • Ostatnio:prawie 9 lat
  • Postów:65
0

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

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

UnlimitedPL
tak to jest MVVM. interfejs INotifyPropertyChanged też powinien być zaimplementowany w osobnej klasie by do każdego ViewModelu nie musieć jej tworzyć wewnątrz. potem tylko dziedziczenie tej klasy dla ViewModelu.
QU
a czemu nie są klikalne elementy?
QU
nie pomaga. chodzi o to ze te itemy sa brzydkie,teraz zobaczylam sa klikalne (nawet nie robiac tutka z linka) ale klika sie obok tekstu a na tekscie...
UnlimitedPL
Jeśli chcesz zdefiniować sobie wygląd takiego Itema to definiujesz ten wygląd w ItemTemplate TreeView'a
QU
  • Rejestracja:ponad 9 lat
  • Ostatnio:prawie 9 lat
  • Postów:65
0

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

Kopiuj
<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:

Kopiuj
<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??

edytowany 1x, ostatnio: quechua
UnlimitedPL
  • Rejestracja:prawie 12 lat
  • Ostatnio:ponad 6 lat
  • Postów:231
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ć:

Kopiuj
...
<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>
...

Kopiuj
> 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?
UnlimitedPL
Margin możesz ustawiać też na wartości ujemne. Chcesz w lewo 5 pikseli to robisz Margin="-5 0 0 0". ItemTemplate to nic innego jak definicja wyglądu pojedynczego w tym przypadku TreeViewItem'a. Możesz tam wsadzić i grafiki i 5 innych tekstów i wszystko inne. Masz nieograniczone możliwości.
UnlimitedPL
To dalej jest TreeViewItem tylko z wyglądem zdefiniowanym przez Ciebie.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.