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);
    }    

更新:各プロパティ (現在は CurrentValue と Frequency) に対して get set メソッドを持つ ViewModel が既にありますが、新しいモデル クラスを作成する代わりに、それに 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

現在のコードは、WPFが推奨する方法に従わない方法で記述されており、現在のコードに逆らって泳ぐと、本来よりもはるかに困難になります。

コードが行うべきことは次のとおりです。

チャネルの(ビュー)モデルクラスを作成します

例えば:

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

ItemsControlの代わりに使用するStackPanel

このようなことを行うWPFの方法は、コントロールをコレクションにバインドすることなので、StackPanelをに置き換えItemsControlます。

をモデルItemsControlのにバインドしますObservableCollection

メインのビューモデルはObservableCollection<ChannelModel>プロパティを公開し、コントロールはそれに直接バインドする必要があります。

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

これにより、他に何もしなくても、コレクションに加えられた変更でコントロールが自動的に更新されます。

を使用しDataTemplateて、各モデルのレンダリング方法を指定します

これまでのところ、チャネルコレクションとの同期を維持するためのコントロールを取得しましたが、各アイテム(チャネルモデル)の表示方法も指定する必要があります。これを行うには、 :DataTemplateResourcesコレクションにを追加します。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 に答える
0

一般的にはDataTemplate、特定のタイプの を作成するという考えがあります。あなたの場合は、ViewModel 用です。

ViewModelたとえば、次のようにDataTemplate を作成します。

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

また、XAML では、ViewModel のリストをバインドする必要があります。

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