[英]Reducing multiple windows with mvvm
我有一个带有几个按钮的主窗口,每个按钮代表不同的对象(同一种),它们需要不同的图形值。使用一个视图和窗口以在同一对象上呈现所有不同对象的最佳方法是什么图(当然是一个时间)取决于我们选择的按钮。
这是视图(在我看来,删除XAML代码对于该问题而言是不必要的):
<layout:SampleLayoutWindow x:Class="AreaChart.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
ResizeMode="CanResizeWithGrip"
xmlns:chart="clr-namespace:Syncfusion.UI.Xaml.Charts;assembly=Syncfusion.SfChart.WPF"
xmlns:local="clr-namespace:PL"
xmlns:layout="clr-namespace:Syncfusion.Windows.SampleLayout;assembly=Syncfusion.Chart.Wpf.SampleLayout"
UserOptionsVisibility="Collapsed"
WindowStartupLocation="CenterScreen" Height="643.287" Width="1250.5"
Title="2017">
<Grid>
<Grid.Resources>
...........................................
<chart:AreaSeries x:Name="AreaSeries" EnableAnimation="True"
**XBindingPath="date"
Label="Favourite"
YBindingPath="rate"
ItemsSource="{Binding CurrenciesHis}"**
ShowTooltip="True" >
<chart:AreaSeries.AdornmentsInfo>
<chart:ChartAdornmentInfo AdornmentsPosition="Bottom"
HorizontalAlignment="Center"
VerticalAlignment="Center"
ShowLabel="True">
<chart:ChartAdornmentInfo.LabelTemplate>
<DataTemplate>
....................................
<ComboBox
ItemsSource="{Binding YearsList}"
SelectedItem="{Binding Year}"
/>
这是ViewModel:
public class ViewModel
{
public ViewModel()
{
Year = DateTime.Now.Year - 1;
UpdateCurrencies();
}
protected void UpdateCurrencies()
{
// Indexs that holds actuall api retrived values
int i, j;
// cR- current rate in string format, urlContents - the whole Api retrived data
string cR, urlContents;
// For api syntx, add 0 or not, depends on the current date syntax
string c;
CurrenciesHis = new ObservableCollection<Model>();//Model objects collection
HttpClient client = new HttpClient();
for (int l = 1; l < 13; l++)
{
if (l < 10)
c = "0";
else
c = "";
// Use the public property Year, not the field _year
var url = "http://data.fixer.io/api/" + Year + "-" + c + l + "-01?access_key=&base=USD&symbols=EUR&format=1";
urlContents = client.GetStringAsync(url).Result;
i = urlContents.IndexOf("EUR");//Finds the desired value from api recived data
j = urlContents.IndexOf("}");
cR = urlContents.Substring(i + 5, (j - 2) - (i + 5));
CurrenciesHis.Add(new Model() { rate = Convert.ToDouble(cR), date = "01/" + l.ToString() });
}
OnPropertyChanged(nameof(CurrenciesHis));
}
private int _year;
public int Year
{
get { return _year; }
set
{
if (_year != value)
{
_year = value;
OnPropertyChanged(nameof(Year));
UpdateCurrencies();
}
}
}
public ObservableCollection<Model> CurrenciesHis { get; private set; }
public System.Collections.IEnumerable YearsList
=> Enumerable.Range(DateTime.Now.Year - 30, 30).ToList().AsReadOnly();
}
这是主窗口,我们通过单击打开包含图形的窗口的按钮,选择了要在视图的图形上表示的货币:
<Window x:Class="PL.WindowMenu"
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:PL"
mc:Ignorable="d"
Title="WindowMenu" Height="643.287" Width="1250.5" WindowStartupLocation="CenterScreen">
<StackPanel Margin="0,0,2,2" RenderTransformOrigin="0.511,0.536">
<StackPanel.Background>
<ImageBrush/>
</StackPanel.Background>
<Grid Height="612" x:Name="NewGrid">
<Button Style="{StaticResource ButtonStyle}" HorizontalAlignment="Left" Height="92" Margin="346,221,0,0" VerticalAlignment="Top" Width="290" Click="Button_Click"></Button>
<Button Style="{StaticResource ButtonStyle}" HorizontalAlignment="Left" Height="92" Margin="346,221,0,0" VerticalAlignment="Top" Width="290" Click="Button_Click2" Command="{Binding Path=ButtonClickCommand}" CommandParameter="{Binding}"></Button>
<Button Style="{StaticResource ButtonStyle}" HorizontalAlignment="Left" Height="92" Margin="346,221,0,0" VerticalAlignment="Top" Width="290" Click="Button_Click3"></Button>
</Grid>
</stackpanel>
</window>
主窗口的ViewModel:
class RTViewModel : ObservableCollection<RTModel>
{
IBL bl;
public ICommand ButtonClickCommand
{
get
{
return new EuroClickCommand();
}
}
public void OpenGraph()
{
AreaChart.MainWindow myWindow = new AreaChart.MainWindow();
myWindow.Show();
//Window.GetWindow(this).Hide();
}
public RTViewModel()
{
}
EuroClickCommand:
class EuroClickCommand : ICommand
{
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
var viewModel = (RTViewModel)parameter;
viewModel.OpenGraph();
}
}
执行此任务的最佳方法是什么?
您有几种选择可以实现此目的 。 一种是在视图中显示多个图形,其中一个具有Visibility = Visibility.Visible
,另一个具有Visibility.Collapsed
。 如果您的图表有所不同,那很好。
但是另一种资源较少的解决方案是仅更改绑定的ObervableCollection 。 我建议在以下MVVM实现中使用按钮来更改图形。
在您看来:
<chart:AreaSeries ItemsSource="{Binding CurrenciesHis}"/>
<Button Command="{Binding ChooseGraphCommand}" CommandParameter="1"/>
<Button Command="{Binding ChooseGraphCommand}" CommandParameter="2"/>
<Button Command="{Binding ChooseGraphCommand}" CommandParameter="3"/>
并在您的ViewModel中:
private ValuesType _currenciesHis;
public ValuesType CurrenciesHis
{
get => _currenciesHis;
set
{
if (value == _currenciesHis) return;
_currenciesHis = value;
OnPropertyChanged();
}
}
private ICommand _chooseGraphCommand;
public ICommand ChooseGraphCommand => _chooseGraphCommand ??
(_chooseGraphCommand= new DelegateCommand(
s =>
{
switch(s)
{
default:
case 1:
CurrenciesHis = graph1; // graph1 contains your data
case 2:
CurrenciesHis = graph2;
case 3:
CurrenciesHis = graph3;
}
// or
CurrenciesHis = allGraphs[s-1]; // array or List of your data
},
s => true));
// implementation of INPC
public event PropertyChangedEventHandler PropertyChanged;
[YourNameSpace.Annotations.NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
和这个辅助类:
public class DelegateCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public event EventHandler CanExecuteChanged;
public DelegateCommand(Action<object> execute) : this(execute, null) {}
public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter);
public void Execute(object parameter) => _execute(parameter);
public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
但是,在您的注释中:
[AttributeUsage(AttributeTargets.Method)]
public sealed class NotifyPropertyChangedInvocatorAttribute : Attribute
{
public NotifyPropertyChangedInvocatorAttribute() { }
public NotifyPropertyChangedInvocatorAttribute([NotNull] string parameterName)
{
ParameterName = parameterName;
}
[CanBeNull] public string ParameterName { get; private set; }
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.