Click here to Skip to main content
15,868,164 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I created view model class in another class. So I also created a border which is showing Engine values(temperature, etc.) I have approximately 60 engines. So I dont want to copy-paste that values. I want to create a Datatemplate or controltemplate after that I want to call that template for each engine borders. I tried many ways but I am stuck.

What I have tried:

public class Machines
{
    public Machines()
    {
        Machine1  = new Status();
        Machine2  = new Status();
        Machine3  = new Status();
        Machine4  = new Status();
        Machine5  = new Status();
        //..... I have 60 machines.
     }

    public Status Machine1 { get; set; }
    public Status Machine2 { get; set; }
    public Status Machine3 { get; set; }
    public Status Machine4 { get; set; }
    public Status Machine5 { get; set; }
    //..... I have 60 machines.}
}



another Status Class:

public class Status : INotifyPropertyChanged
{
    public Status()
    {
        chronometer = new Stopwatch();

        timer = new DispatcherTimer();
        timer.Tick += new EventHandler(UpdateTimer_Tick);
        timer.Interval = new TimeSpan(0, 0, 0, 0, 500);
    }

    DispatcherTimer timer { get; set; }
    Stopwatch chronometer { get; set; }

    private string _machinename;
    private int _piece;
    private double _temperature;
    private string _timeSpan;
    private string _imagePath;
    public string MachineName
    {
        get { return _machinename; }
        set
        {
            _machinename = value;
            OnPropertyChange("MachineName");
        }
    }
    public int Piece
    {
        get { return _piece; }
        set
        {
            _piece = value;
            OnPropertyChange("Piece");
        }
    }
    public double Temperature
    {
        get { return _temperature; }
        set
        {
            _tempColor = GetTempForeGroundColor(value);
            _temperature = value;
            OnPropertyChange("Temperature");
            OnPropertyChange("TempColor");
        }
    }
    public string TimeSpan
    {
        get { return _timeSpan; }
        set
        {
            _timeSpan = value;
            OnPropertyChange("TimeSpan");
        }
    }
    public string ImagePath => _imagePath;


// on top, I have little more properties. So I am passing them.
Here is my border that I take Engine values; The thing I want to do is; create border for each engine then binding that template with it.
Is there any best way to complete those? Thanks.


<Page.DataContext>
        <local1:Machines/>
</Page.DataContext>

<Border Grid.Column="1" Grid.Row="0" Height="132" Width="163" BorderThickness="1" BorderBrush="#ff737373" CornerRadius="8">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition/>
                                <ColumnDefinition/>
                            </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition/>
                                <RowDefinition/>
                                <RowDefinition/>
                                <RowDefinition/>
                                <RowDefinition/>
                            </Grid.RowDefinitions>
                            <TextBlock Text="{Binding Machine2.MachineName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" TextAlignment="Center" FontSize="20" FontFamily="Century Gothic" Grid.ColumnSpan="2" Grid.Row="0" />
                            <Image Grid.Row="1" Source="{Binding Machine2.ImagePath, UpdateSourceTrigger=PropertyChanged}" Grid.ColumnSpan="2" Width="35" Margin="63,9,63,8" Grid.RowSpan="2"/>
                            <TextBlock Text="{Binding Machine2.Piece, Mode=TwoWay, StringFormat='{}{0} +',   UpdateSourceTrigger=PropertyChanged}" Grid.Row="3" Grid.Column="0" TextAlignment="Center" Padding="2" FontFamily="century gothic" FontSize="18"/>
                            <TextBlock Text="{Binding Machine2.Temperature, Mode=TwoWay, StringFormat='{}{0} °C',   UpdateSourceTrigger=PropertyChanged}" Foreground="{Binding Machine2.TempColor}" Grid.Row="3" Grid.Column="1" TextAlignment="Center" Padding="2" FontFamily="century gothic" FontSize="18"/>
                            <Border Grid.Row="4" Grid.ColumnSpan="2" BorderThickness="1" Width="140" Height="12" CornerRadius="10" Background="{Binding Machine2.StatusColor}" Visibility="{Binding Machine2.BorderVisibility}"/>
                            <TextBlock Text="{Binding Machine2.TimeSpan, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding Machine2.TimeSpanVisibility}" Grid.Row="4" Grid.ColumnSpan="2" TextAlignment="Center" Padding="2" FontFamily="century gothic" FontSize="18"/>
                        </Grid>
                    </Border>


I tried as bottom but result is nothing;

        <ControlTemplate  x:Key="MachineBorderTemplate">
            <Border Height="132" Width="163" BorderThickness="1" BorderBrush="#ff737373" CornerRadius="8">
......
            </Border>
        </ControlTemplate>


And I tried this in page;

<ContentPresenter Grid.Column="9" Grid.Row="5" ContentTemplate="{Binding MachineBorderTemplate}" ></ContentPresenter>

But the problem is, How will I bind for each border with Machines? e.g.
MachineName = "{Machine45.MachineName}"
Temperature = "{Machine2.Temperature}"
Posted
Updated 23-May-22 0:33am
v5

1 solution

Why do you have 60 different MachineX properties instead of just having an ObservableCollection<Status>? Having individual fields is going to not only make your code incredibly difficult to maintain, but you're also going to make an incredible amount of work with binding it in WPF.

I recommend that you switch to using an observable collection, insert the 60 machine statuses into there, and then use something like ItemsControl[^] to loop over the collection and then display the elements you need. You can see on the page I've linked there's an example where they bind to the element in the collection like so:

C#
<ItemsControl.ItemTemplate>
  <DataTemplate>
    .. create your view here
  </DataTemplate>
</ItemsControl.ItemTemplate>
 
Share this answer
 
Comments
[no name] 23-May-22 6:42am    
Can you write a basic example with ObservableCollection<status>?
Chris Copeland 23-May-22 6:48am    
I'm not going to write any WPF as that would require me to create a VS solution and write up a lot of code, but from your Machines class it would look something like:

public class Machines {

  public Machines() {
    Statuses = new ObservableCollection<Status>();
    for (int i = 0; i < 60; i++) {
      Statuses.Add(new Status());
    }
  }

  public ObservableCollection<Status> Statuses {
    get;
    set;
  }
}

From there you can use the binding to the collection such as <ItemsControl ItemsSource="{Binding Statuses}"> which will then automatically bind the elements of the collection to the control. I also believe this registers for PropertyChanged events so if anything changes in one of the statuses, the ItemsControl will update the data template.
[no name] 23-May-22 8:39am    
Thank you very much for your efford @Chris Copeland.
It worked very clearly.
In this way, I developed MV methods.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900