Laden...

MVVM: Commands / RoutedEvents Wie gebe ich ein ButtenClick eines UserControls weiter

Erstellt von Boris0815 vor 13 Jahren Letzter Beitrag vor 13 Jahren 4.948 Views
B
Boris0815 Themenstarter:in
225 Beiträge seit 2008
vor 13 Jahren
MVVM: Commands / RoutedEvents Wie gebe ich ein ButtenClick eines UserControls weiter

Hiho,

ich versuche grad ein ButtonClick-Event eines UserControls an meine MainView weiter zu leiten. Komme da aber nicht weiter.

Erstmal mein Aufbau der Gui.

Die MainView hat einen Container für die UserControls:

<Grid Grid.Row="2" Name="LeftMenu">
            <ContentControl Content="{Binding Path=LeftMenu}"  Margin="-5,5,5,5" HorizontalAlignment="Left" VerticalAlignment="Center"/>
        </Grid>

Im VM der Mainview wird ein UserControl (LeftMenu) gebunden. Dieses besteht aus einer ListBox in der dynamisch Buttons eingefügt werden. Die Anzahl der Buttons kann variieren.
Der XAML des Leftmenus sieht folgendermasen aus:

    <UserControl.Resources>
        <Style TargetType="{x:Type ListBox}">
            <Setter Property="ItemTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <StackPanel Width="100" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="3,3,3,3">
                            <Button Width="100" Height="106" HorizontalAlignment="Center" VerticalAlignment="Center">
                                <Grid>
                                    <Image Margin="3" Source="{Binding Path=Bild}" Stretch="Fill" Width="60" Height="60" HorizontalAlignment="Center" VerticalAlignment="Top"/>
                                    <TextBlock Text="{Binding Path=Text}" HorizontalAlignment="Center"/>
                                </Grid>
                            </Button>
                        </StackPanel>
                    </DataTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </UserControl.Resources>
		<Border CornerRadius="8" BorderThickness="2" Background="White" BorderBrush="Black">
        <Border.Effect>
            <DropShadowEffect BlurRadius="20" ShadowDepth="10"/>
        </Border.Effect>
        <ListBox Name="ButtonList" ItemsSource="{Binding ButtonControls}" Background="Transparent" BorderBrush="Transparent" HorizontalAlignment="Center" VerticalAlignment="Center"/>
		</Border>

Was muss ich nun tun, damit ich die ClickEvents der Buttons in meiner Mainview, bzw. desen VM, erhalte? Muss ich dazu eigene Commands schreiben?

Gruß

Boris

5.299 Beiträge seit 2008
vor 13 Jahren

Jo, mit Commands könnte sowas gehen.
Aber insgesamt scheinst du mir nicht hinreichend zu differenzieren:

Im VM der Mainview wird ein UserControl (LeftMenu) gebunden.

Bindungen sollte man im View einstellen, nicht im Viewmodel.

Was muss ich nun tun, damit ich die ClickEvents der Buttons in meiner Mainview, bzw. desen VM, erhalte?

Beim Command-Konzept wird bei Click das Command im VM des UserControls aufgerufen - das MainView oder sein VM haben zunächstmal nix damit zu tun.

Dein Xaml verstehe ich nicht - ist das so lauffähig?

Wie ist bewerkstelligt, dass dein UserControl im MainView überhaupt erscheint?

Der frühe Apfel fängt den Wurm.

B
Boris0815 Themenstarter:in
225 Beiträge seit 2008
vor 13 Jahren

Hiho,

Bindungen sollte man im View einstellen, nicht im Viewmodel.

Wie meinst Du das? Ich habe das für dasUserControl LeftMenu so gelöst.

MainView:

        <Grid Grid.Row="2" Name="LeftMenu">
            <ContentControl Content="{Binding Path=LeftMenu}"  Margin="-5,5,5,5" HorizontalAlignment="Left" VerticalAlignment="Center"/>
        </Grid>

MainViewVM:

        private UserControl leftMenu;
        public UserControl LeftMenu
        {
            get { return this.leftMenu; }
            set
            {
                if (value != this.leftMenu)
                {
                    this.leftMenu = value;
                    NotifyPropertyChanged("LeftMenu");
                }
            }
        }

Beim Command-Konzept wird bei Click das Command im VM des UserControls aufgerufen - das MainView oder sein VM haben zunächstmal nix damit zu tun.

Ich brauche das ClickEvent in meinem MainViewVM um damit andere Controls freizuschalten. Zur Erklärung was ich überhaupt machen will. In diesem Beitrag ist ein Bild wie die View mal aussehen soll.
Links ist das LeftMenu UserControl. Bei Start des Programms werden mittels MEF dynmisch verschiedene UserControls geladen. Jedes dieser Controls bekommt automatisch einen Button im LeftMenu.
Wenn auf einen dieser Buttons geklickt wird, soll das eigentliche UserControl in der Mitte des Window dargestellt werden. Damit ich zwischen den UserControls hin und herschalten kann brauch ich das Event/Command des Buttons im MainViewVM.

Dein Xaml verstehe ich nicht - ist das so lauffähig?

Das Template macht eigentlich nur das, in der Listview Buttons als Items dargestellt werden. (siehe Bild) Das funktioniert auch so weit.

Gruß

Boris

5.299 Beiträge seit 2008
vor 13 Jahren

krasse vermischung von View und Viewmodel. Das MainViewmodel sollte keine Property vom Typ UserControl anbieten, sondern mw. ein SubViewmodel.
Im Xaml, mittels DataTemplate kann man das dazu passende UserControl definieren.

Also ein Viewmodel enthält vlt. weitere Viewmodels, aber keinen View.

Die Brücke von View zu Viewmodel wird per Databinding geschlagen, im Xaml.

Der frühe Apfel fängt den Wurm.

B
Boris0815 Themenstarter:in
225 Beiträge seit 2008
vor 13 Jahren

Hiho,

wir versuchen gerade Ordnung in unser MVVM zu bringen. Wir sind uns aber garnicht sicher ob das überhaupt so machbar ist.

Du hast gesagt:

Das MainViewmodel sollte keine Property vom Typ UserControl anbieten, sondern mw. ein SubViewmodel.
Im Xaml, mittels DataTemplate kann man das dazu passende UserControl definieren.

Also ein Viewmodel enthält vlt. weitere Viewmodels, aber keinen View.

Das ist soweit auch klar. Aber können wir das in unserem Fall auch machen?
Wir haben eine MainView die verschiedene UserControls beinhaltet. Diese werden mit MEF geladen. (Siehe Bild)
Momentan wollten wir es so machen, dass das VM der MainView den MEF Container hat und aus dlls die einzelnen UserControls holt. Ein UserControl (View und VM) sind je in einer dll.
Kann man das mit MVVM umsetzen? Wie sollen wir View und VM der Usercontrols getrennt behandeln und dann wieder binden? Wie leiten wir Events/Commands der UserControls am besten an die MainView weiter (Dynamik)?

Gruß

Boris

1.044 Beiträge seit 2008
vor 13 Jahren

Hallo Boris0815,

du schmeißt alles in einen Topf. Das geht so nicht. Programmier es so, wie es auch die anderen machen. Es gibt sog. "Best Practices". Mehr dazu findest du in diesem Artikel Model-View-ViewModel (MVVM) Explained (Silverlight).

MEF und MVVM ist wieder so eine Sache. Verwende MEFedMVVM oder Cinch.

Dein Ziel ist sehr durcheinander und es gibt mehrere Probleme. Versuch es mal zu differenzieren.

zero_x

B
Boris0815 Themenstarter:in
225 Beiträge seit 2008
vor 13 Jahren

Hallo zero_x,

danke für die Links. Gerade der erste ist meiner Meinung nach eine sehr gute Erklärung von MVVM. Zum Teil wenden wir das auch schon so an.

Ich glaube Du hast falsch verstanden für was wir MEF nutzen wollen. Wir nutzen MEF nicht um View und ViewModel zu verbinden wie es MEFedMVVM nutzt. Wir nutzen MEF um komplette Komponenten in unsere Applikation zu laden. Eine solche Komponente kann auch visuelle Elemente beinhalten. Dann wird intern in der Komponente MVVM angewendet.

Als Beispiel ein Dialog:

Wir haben unsere MainApplikation, die mit MEF dynamisch Komponenten lädt. MEF kennt dabei verschiedene Interfaces. In diesem Beispiel (ausgedachte Namen) z.B. IDialog, und IUCResources. In IDialog wären dann Informationen die für den Dialog wichtig wären, wie z.B. Close-Command (Event?). In IUCResources stecken Informationen wie z.B. Name der Komponente oder Text für einen Button. In der Komponente Dialog steckt dann ein UserControl mit View und ViewModel.
Unser Ziel ist es, dass MEF Komponeten lädt und diese automatisch in der Applikation zur Verfügung stellt. Über IUCResources wird der Dialog z.B. an einen Button in der MainView gebunden. Wenn auf diesen Button geklickt wird, wird das UserControl in einem Container der Mainview dargestellt.

Unser Problem bei der Architektur ist es nun, wie wir die Kommunikation zwischen unseren Komponenten und der MainApplikation steuern.

Gruß

Boris

W
955 Beiträge seit 2010
vor 13 Jahren

Wie leiten wir Events/Commands der UserControls am besten an die MainView weiter (Dynamik)? Hi,
Du könntest die VMs durch Controller führen welche die Commands/Delegates entsprechend binden/routen.

Xaml UserControl:


<Button Command="{Binding SaveCommand}" CommandParameter="Save pressed in UserControl" >Speichern</Button>

VM UserControl


        private ICommand saveCommand;

        public ICommand SaveCommand 
        { 
            get { return saveCommand; }
            set { 
            
                if (saveCommand != value)
                {
                    saveCommand = value;
                    RaisePropertyChanged("SaveCommand");
                }
            }
        }

Xaml MainView:


<TextBox Text="{Binding Result}" ></TextBox >

VM MainView:


        private String result;

        public String Result
        { 
            get { return result; }
            set { 
            
                if (result!= value)
                {
                    result= value;
                    RaisePropertyChanged("Result");
                }
            }
        }

Controller:


[Import(typeof(IUserViewModel))]
public IUserViewModel MyControl { get; set; };
[Import]
public MainViewModel MyMainView { get; set; };

public void LoadUserControl1()
{

    MyControl.SaveCommand = new DelegateCommand((p) => SetResult(p));
}

private void SetResult(object p)
{

     MyMainView.Result = p.ToString();  
}


* Ich habe das aus dem kopf geschrieben, weiß nicht ob das fehlerfrei ist.
* die korrekten MEF-Bindungen (Lazy Loading ...) mußt Du selber implementieren, weiß nicht was Du brauchst (oder container.GetExportedValue<T>)
* DelegateCommand ist aus dem WAF (waf.codeplex.com). Diu solltest Dir ein Framework suchen welches solche Funktionalitäten anbietet.
* Die Schnittstellen (hier IUserViewModel ) mußt Du entsprechend definieren. Falls ICommand Dir zu WPF lastig ist kannst Du es vorher ja in ein Action<T> etc wandeln