0

对于我的项目,我正在尝试创建一个连接到工具集并将信号推送到其中的信号通道生成器。

我遇到的问题是,我以文本框代码位于代码隐藏文件中的形式获得了项目,并且我希望它们位于 xaml 中。

我有一个变量来控制可以更改的通道数(视图模型)。它能够在窗口上创建同一视图模型的多个实例。这允许在工具内选择与之通信的不同目标,并能够将信号泵送到每个目标。

这是当前在 XAML 中的代码:

    <Window x:Class="SigGeneratorMVVM.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:SigGeneratorMVVM"
        Title="Signal Generator" Height="370" Width="734" >
    <StackPanel Name="MyWindow">
        <!--<TextBox Height="23" HorizontalAlignment="Left" Margin="91,20,0,0" Name="CurrentValDisplay" VerticalAlignment="Top" Width="120" />-->
    </StackPanel>
</Window>

这是 mainwindow.cs 的代码

public partial class MainWindow : Window
    {
        List<ViewModel> gViewModels;

        int gNumChannels = 1;
        private System.Threading.Timer mViewUpdateTimer;
        private TimerCallback mViewTimerCallback;

        private UtilityParticipant mParticipant;

    public MainWindow()
    {
        InitializeComponent();

        // Connect as UtilityParticipant            
        ConnectMesh();

        gViewModels = new List<ViewModel>();           

        for (int i = 0; i < gNumChannels; i++)
        {
            gViewModels.Add(new ViewModel(mParticipant));

            TextBlock CurrentValueText = new TextBlock();
            CurrentValueText.Text = "Current Value:";
            CurrentValueText.Margin = new Thickness(5);

            TextBox CurrentValueBox = new TextBox();
            CurrentValueBox.Width = 120;
            CurrentValueBox.Name = "CurrentValDisplay" + i.ToString();
            CurrentValueBox.HorizontalAlignment =                                                System.Windows.HorizontalAlignment.Left;
            CurrentValueBox.Margin = new Thickness(10);
            CurrentValueBox.SetBinding(TextBox.TextProperty, "CurrentValue");

            //CurrentValDisplay.Name = "CurrentValDisplay" + i.ToString();
            //CurrentValDisplay.SetBinding(TextBox.TextProperty, "CurrentValue");

            TextBlock CurrentFrequencyText = new TextBlock();
            CurrentFrequencyText.Text = "Frequency:";
            CurrentFrequencyText.Margin = new Thickness(5);

            TextBox CurrentFrequencyBox = new TextBox();
            CurrentFrequencyBox.Width = 120;
            CurrentFrequencyBox.Name = "CurrentFrequencyDisplay" + i.ToString();
            CurrentFrequencyBox.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
            CurrentFrequencyBox.Margin = new Thickness(10);
            CurrentFrequencyBox.SetBinding(TextBox.TextProperty, "Frequency");

            Slider FrequencySlider = new Slider();
            FrequencySlider.Width = 200;
            FrequencySlider.Name = "FrequencySet" + i.ToString();
            FrequencySlider.Value= 10;
            FrequencySlider.Maximum = 10;
            FrequencySlider.Minimum = 0.1;
            FrequencySlider.SetBinding(Slider.ValueProperty, "Frequency");                    

            //Create a new stackpanel
            StackPanel sp = new StackPanel();
            sp.Orientation = Orientation.Vertical;

            //Set DataContext of the StackPanel
            sp.DataContext = gViewModels[i];

            //Add controls created above to the StackPanel
            sp.Children.Add(CurrentValueText);
            sp.Children.Add(CurrentValueBox);
            sp.Children.Add(CurrentFrequencyText);
            sp.Children.Add(CurrentFrequencyBox);
            sp.Children.Add(FrequencySlider);

            //Add the StackPanel to the window

            MyWindow.Children.Add(sp);

        }

        mViewTimerCallback = this.UpdateView;
        mViewUpdateTimer = new System.Threading.Timer(mViewTimerCallback, null,     100, 20);
    }    

更新:我已经有一个 ViewModel,它为每个属性(现在是 CurrentValue 和 Frequency)设置了方法,将 DataTemplate 和 ItemsControl 绑定到它而不是创建一个新的模型类就足够了吗?

    private SigGenChannel mSigGenChannel;

    //Constructor
    public ViewModel(UtilityParticipant aParticipant)
    {
        mSigGenChannel = new SigGenChannel(aParticipant);
    }


    public string CurrentValue
    {
        get
        {
            return mSigGenChannel.CurrentValue.ToString();
        }

        set
        {
            mSigGenChannel.CurrentValue = double.Parse(value);
            RaisePropertyChanged("CurrentValue");
        }
    }

    public double Frequency
    {
        get
        {
            return mSigGenChannel.Frequency;
        }

        set
        {
            mSigGenChannel.Frequency = value;
            RaisePropertyChanged("Frequency");
        }
    }

    public double Amplitude
    {
        get
        {
            return mSigGenChannel.Amplitude;
        }

        set
        {
            mSigGenChannel.Amplitude = value;
            RaisePropertyChanged("Amplitude");
        }
    }

    public void RefreshValue()
    {
        //A bit of a cheat, but we provide a means to poke the Viewmodel
        //And raise a property change event
        RaisePropertyChanged("CurrentValue");
    }

这也是 SigChannel 模型:

 class SigGenChannel
{
    #region Private members
    private UtilityParticipant mParticipant;
    private double mCurrentValue;
    private double mFrequency;
    private double mAmplitude;
    private double mTarget;
    private double mOffset;
    private double mCurrentStepTime;
    private DateTime mStartTime;
    private System.Threading.Timer mTimer;
    private TimerCallback mTCallback;
    private int mUpdateInterval = 10;
    #endregion

    #region Public members
    public double CurrentValue
    {
        get
        {
            return mCurrentValue;
        }
        set
        {
            mCurrentValue = value;
        }
    }        

    public double Frequency
    {
        get
        {
            return mFrequency;
        }

        set
        {
            mFrequency = value;
        }
    }

    public double Amplitude
    {
        get
        {
            return mAmplitude;
        }
        set
        {
            mAmplitude = value;
        }
    }

    public double Target
    {
        get
        {
            return mTarget;
        }
        set
        {
            mTarget = value;
        }
    }
    #endregion


    //Constructor
    public SigGenChannel(UtilityParticipant aParticipant)
    {
        mParticipant = aParticipant;
        mCurrentValue = 10;
        mFrequency = 200;
        mAmplitude = 100;
        mOffset = 0;
        mCurrentStepTime = 0;
        mStartTime = DateTime.Now;
        mTCallback = this.Update;
        mTimer = new System.Threading.Timer(mTCallback, null, 500, mUpdateInterval);
        //Array enumData = Enum.GetNames;
        //RefreshItems();
        //Temp Code....!
        Collection lCollection = mParticipant.GetCollection("DefaultNodeName.NodeStats");
        lCollection.Publish();
    }

    private void Update(object StateInfo)
    {
        TimeSpan span = DateTime.Now - mStartTime;
        mCurrentStepTime = span.TotalMilliseconds / (double)1000;

        mCurrentValue = (Math.Sin(mCurrentStepTime * (mFrequency * 2 * Math.PI)) * mAmplitude / 2) + mOffset;

        //Temp Code...!
        Collection lCollection = mParticipant.GetCollection("DefaultNodeName.NodeStats");
        Parameter lParameter = lCollection.GetParameter("CPUPercent");
        lParameter.SetValue(mCurrentValue);
        lCollection.Send();
4

2 回答 2

0

DataTemplate通常的想法是为特定类型创建一个,在您的情况下,它是为 ViewModel 创建的。

为您创建一个 DataTemplate ViewModel,例如:

<DataTemplate DataType={x:Type local:ViewModel}>
    <TextBox Text="{Binding ViewModelTextProperty}" />
</DataTemplate>

而且在您的 XAML 中,您还必须绑定您的 ViewModel 列表

<ItemsControl ItemsSource="{Binding myListOfViewModels}"/>
于 2013-01-29T11:39:51.280 回答
0

当前代码的编写方式不遵循 WPF 建议的做法,并且逆流而上使事情变得比当时更难。

代码应该做的是:

为通道创建(视图)模型类

例如:

class ChannelModel
{
    public int Value { get; set; }
    public int Frequency { get; set; }
}

使用 aItemsControl而不是 aStackPanel

WPF 执行此类操作的方法是将控件绑定到集合,因此将 替换StackPanelItemsControl.

绑定ItemsControlObservableCollection模型中的一个

您的主视图模型应该公开一个ObservableCollection<ChannelModel>属性,并且控件应该直接绑定到该属性:

<ItemsControl ItemsSource="{Binding CollectionOfChannelModels}"/>

这可确保控件会随着对集合所做的任何更改而自动更新,而无需您执行任何其他操作。

使用 aDataTemplate指定每个模型的渲染方式

到目前为止,我们已经获得了与您的频道集合保持同步的控件,但我们还需要告诉它应该如何显示每个项目(频道模型)。为此,请将 a 添加DataTemplate到 的Resources集合中ItemsControl

<ItemsControl.Resources>
  <DataTemplate DataType={x:Type local:ChannelModel}>
    <StackPanel Orientation="Horizontal">
      <TextBlock Text="Value" />
      <TextBox Text="{Binding Value}" />
    </StackPanel>
  </DataTemplate>
</ItemsControl.Resources>
于 2013-01-29T11:41:00.913 回答