У меня есть этот вид (фрагмент) с 2 кнопками. Если я нажму левую кнопку, откроется вид 2. Если я нажму правую кнопку, откроется вид 3. Я использую Caliburn Micro. Следовательно, значение x: Name кнопки - это имя метода модели представления, которое вызывается после нажатия кнопки.
View1:
<StackPanel Name="PnlButtons"
Grid.Row="1"
Grid.ColumnSpan="2"
HorizontalAlignment="Center"
Orientation="Horizontal"
Opacity="1">
<Button x:Name="ArtikelAuswahl"
Background="Bisque"
Content="Artikel auswählen"
Width="170" Height="25"
FontFamily="Verdana">
</Button>
<Button x:Name="SonderAuswahl"
Background="BlanchedAlmond"
Content="Sonderartikel hinzufügen"
Width="170" Height="25"
FontFamily="Verdana">
</Button>
</StackPanel>
Вот 2 метода, которые вызываются после нажатия кнопки. Вы можете видеть, что они имеют одинаковое имя. Теперь люди говорят, что открыть модель внутри модели запрещено. Вот почему я использую экземпляр IWindowManager winmanager внутри своих методов, когда я хочу открыть новое представление. Вместо создания нового экземпляра представления, я создаю новый экземпляр viewmodel! Первый вопрос: это противоречит правилам MVVM?
ViewModel1:
public class CreateLieferscheinViewModel : Conductor<object>
{
private IWindowManager winmanager = new WindowManager();
public InventurartikelViewModel inventur = new InventurartikelViewModel();
public SonderartikelViewModel sonder = new SonderartikelViewModel();
public void ArtikelAuswahl()
{
wwinmanager.ShowWindow(inventur, null, null);
}
public void SonderAuswahl()
{
winmanager.ShowWindow(sonder,null,null);
}
/* ToBeImplemented: Invoke this method once `Artikelliste` is filled!!! */
public void ArtikellisteUmformen()
{
for (int k = 0; k < inventur.Artikelliste.Count; k++)
{
Artikelsammlung.Add(new ArtikelModel()); //every selected article will get added to Artikelsammlung
//get each selected article unfiltered (unformatted)
Artikelsammlung[k].Bezeichnung = inventur.Artikelliste[k].ToString();
//Extract the unit out of the Artikel-String
Artikelsammlung[k].Einheit = Zeichenketten.TextFindenVonBisEnde(Artikelsammlung[k].Bezeichnung, "<", ">");
//remove "in <Einheit>" from the Artikel-String
Artikelsammlung[k].Bezeichnung = Zeichenketten.EinheitEntfernen(Artikelsammlung[k].Bezeichnung);
/*
* Bezeichnung and Einheit are now properly formatted...
*/
}
}
}
private ObservableCollection<ArtikelModel> _artikelsammlung;
public ObservableCollection<ArtikelModel> Artikelsammlung
{
get { return _artikelsammlung; }
set
{
_artikelsammlung = value;
OnPropertyChanged("Artikelsammlung");
}
}
Хорошо, теперь давайте скажем, что вызывается ArtikelAuswahl . Благодаря Caliburn Micro, View2 показывает:
View2:
<Window x:Class="Lieferscheine.Views.InventurartikelView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Lieferscheine.Views"
xmlns:main="clr-namespace:Lieferscheine"
xmlns:cal="http://www.caliburnproject.org"
mc:Ignorable="d" Title="Inventurartikel suchen"
Height="450" Width="370">
<StackPanel Height="423" VerticalAlignment="Bottom">
<Label Name="lblArtikelbezeichnung" Content="Artikelbezeichnung:" Margin="20, 20, 20, 0"></Label>
<TextBox Name="BezText"
Width="Auto"
Margin="20, 0, 20, 0"
IsEnabled="{Binding Path=BezEnabled}"
cal:Message.Attach="[Event KeyUp] = [Action KeyUpBez($executionContext)]">
</TextBox>
<Label Name="lblLieferant" Content="Lieferant:" Margin="20, 0, 20, 0"></Label>
<TextBox Name="LiefText"
Width="Auto"
Margin="20, 0, 20, 0"
IsEnabled="{Binding Path=LiefEnabled}"
cal:Message.Attach="[Event KeyUp] = [Action KeyUpLief($executionContext)]">
</TextBox>
<Button Name="SucheArtikel"
Content="Suchen"
Width="100" Height="25"
Margin="20, 10,240, 10">
</Button>
<Button x:Name="GesamteListeAnzeigen"
Content="Gesamte Liste anzeigen"
Width="150" Height="26"
Margin="0, -50, 20, 0"
HorizontalAlignment="Right"/>
<main:MultipleSelectionListBox
x:Name="LboxAddArtikel"
SelectionMode="Multiple"
Width="320" Height="220"
Margin="20, 10, 20, 10"
BindableSelectedItems="{Binding Path=MyCollectionOfSelectedIDs}">
</main:MultipleSelectionListBox>
<Button x:Name="FuegeArtikelHinzu"
Content="Hinzufügen"
Width="100" Height="25">
</Button>
</StackPanel>
View2 - это данные, привязанные к ViewModel2. Но прежде чем я покажу вам ViewModel2, я хочу показать вам, что я могу сделать в View2:
Я выбираю 3 статьи из списка и нажимаю на Кнопка внизу view2
для добавления этих статей в список:
<Button x:Name="FuegeArtikelHinzu"
Content="Hinzufügen"
Width="100" Height="25">
</Button>
Статьи добавляются в список по методу FuegeArtikelHinzu
в viewmodel2
:
ViewModel2:
public class InventurartikelViewModel : Screen
{
private List<string> _artikelliste = new List<string>();
public List<string> Artikelliste
{
get { return _artikelliste; }
set
{
_artikelliste = value;
OnPropertyChanged("Artikelliste");
}
}
public bool ArtikellisteUpdated()
{
Filled = Artikelliste != null ? true : false;
return Filled;
}
private bool _filled;
public bool Filled
{
get
{
return _filled;
}
set
{
_filled = value;
OnPropertyChanged("Filled");
if(_filled == true)
{
//TO BE IMPLEMENTED
//then invoke ViewModelA's method `ArtikellisteUmformen()`
}
_filled = false; //I believe I would need to set _filled back
//to false to prevent overflow. Otherwise ViewModelA's method
//`ArtikellisteUmformen()` would get invoked over and over again because
//_filled is always true from now on. Is that correct?
}
}
public void FuegeArtikelHinzu()
{
try
{
//This adds only the multiple selected items to a list
var multi = MyCollectionOfSelectedIDs;
int i = 0;
foreach (string item in multi)
{
Artikelliste.Insert(i, item);
i++;
}
MessageBox.Show("Artikel hinzugefügt!"); //ok, all added...
//call `ArtikellisteUpdated()` and set Property `Filled` (=`Artikelliste` is filled) to true
ArtikellisteUpdated(); //true unless null
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Zuerst Artikel auswählen!"); //you must select an article first...
}
}
}
И вот моя проблема! Мне нужны выбранные статьи в списке artikelliste
В МОЕЙ МОДЕЛИ ВИДА1 !!! Но я зашел в тупик. Я слышал, что это решается путем внедрения службы IMessenger, но я не понимаю, как это работает в моем примере. Что мне нужно сделать, чтобы передать artikelliste
в ViewModel1
в соответствии с моим примером? Если вы не знакомы с Caliburn Micro, опубликуйте другое решение, с нуля или с фреймворком, я не против. Заранее благодарен за любую помощь!
РЕДАКТИРОВАТЬ:
Теперь я могу получить доступ к ViewModel2 и его Artikelliste
свойство в ViewModel1. Тем не менее, я хотел бы вызвать метод ViewModel1 ArtikellisteUmformen()
, как только обновится Artikelliste
ViewModel2. Как я могу это сделать? Вот что я хотел бы сделать:
Когда заполнено Artikelliste
, вы можете вызвать событие в ViewModel2, например, ArtikelListeUpdated. ViewModel1 прослушивает это событие и реагирует на него в случае необходимости. Вам даже не нужно событие, если вам не нужно реагировать на него немедленно.