I have a Window with 6 listboxes, i am trying to make a little car database but i have problems with my bindings in the second listbox. When i try to click on a manufacturer in the first listbox the binding doesnt work.
<Window x:Class="Autolab.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="500" Width="700"
Loaded="Window_Loaded_1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="119*" />
<ColumnDefinition Width="116*" />
<ColumnDefinition Width="137*" />
<ColumnDefinition Width="137*" />
<ColumnDefinition Width="134*" />
<ColumnDefinition Width="134*" />
</Grid.ColumnDefinitions>
<ListBox x:Name="hersteller" Grid.Column="0" DisplayMemberPath="h_name" SelectedValuePath="h_id"/>
<ListBox x:Name="marke" Grid.Column="1"
ItemsSource="{Binding SelectedItem.marken, ElementName=hersteller}" />
<ListBox x:Name="kraftstoff" Grid.Column="2" />
<ListBox x:Name="art" Grid.Column="3" />
<ListBox x:Name="werkstatt" Grid.Column="4" />
</Grid>
this is were i have my Collection
public partial class herstellers
{
public herstellers()
{
this.marken = new HashSet<marke>();
}
public int h_id { get; set; }
public string h_name { get; set; }
public virtual ICollection<marke> marken { get; set; }
}
}
First of all, I would suggest using ObservableCollection rather than HashSet with a ListBox
public partial class herstellers
{
public herstellers()
{
this.marken = new ObservableCollection<marke>();
}
public int h_id { get; set; }
public string h_name { get; set; }
public virtual ICollection<marke> marken { get; set; }
}
Next, assuming your marken class, you must have at least a property that implements ICollection so that the ItemsSource on your second list box can get populated.
public class Marken
{
// Assuming this marke is populated.
public ObservableCollection<int> marke { get; set; }
}
Related
I am having really weird issues with memory leak and I cannot find source after long hours of testing, debugging and trial/error attempts.
The source of memory leak is reloading object base on push from subject. On which part I load current database values and add it to SourceCache.
This part is getting the push, to initiate reload
this.databaseSignalRClient
.UpdatedObservable<JobLine>()
.WhereNotNull()
.Where(x => JobLinesCache.Lookup(x.Id).HasValue)
.SelectMany(LoadJobLine)
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(jl => JobLinesCache.AddOrUpdate(jl));
Here I have the LoadJobLine func
private async Task<JobLine> LoadJobLine(DbNotification dbNotification)
{
using var repo = Locator.Current.GetService<IWmsRepository>();
return await repo.Job.JobLineRepository.FindAsync(dbNotification.Id);
}
And this is how I provide the ViewModels to UI:
private readonly ReadOnlyObservableCollection<JobLineViewModel> jobLineViewModels;
public ReadOnlyObservableCollection<JobLineViewModel> JobLineViewModels => jobLineViewModels;
JobLinesCache.Connect()
.SortBy(jl => jl.CaseNo)
.Transform(jl => new JobLineViewModel(jl))
.ObserveOn(RxApp.MainThreadScheduler)
.Bind(out jobLineViewModels)
.Subscribe();
This is the created ViewModel:
public class JobLineViewModel : ReactiveObject
{
public JobLineViewModel(
JobLine jobLine
)
{
JobLine = jobLine;
}
[Reactive]
public JobLine JobLine { get; private set; }
[Reactive]
public string ContainingItemsString { get; private set; }
}
At last binding collection to UI:
this.WhenActivated(d =>
{
this.OneWayBind(ViewModel, vm => vm.JobLineViewModels, v => v.TestIC.ItemsSource)
.DisposeWith(d);
});
I did test out virtualizing stack panel and without.
<ItemsControl x:Name="TestIC">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
And for the issue. The JobLineViewModel is for some reason not getting garbage collected. I simulate it by pinging the signalR update every 10ms.
I am seriously clueless what is making the JobLineView staying alive. I can post code of it as well, but I dont see any issue...:
<rx:ReactiveUserControl x:Class="Mtc.UserControls.JobLineView"
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:Mtc.UserControls"
mc:Ignorable="d"
x:TypeArguments="vm:JobLineViewModel"
xmlns:rx="http://reactiveui.net"
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:vm="clr-namespace:Wms.Mtc.ViewModels;assembly=Wms.Mtc"
d:DesignHeight="450" d:DesignWidth="800">
<md:Card Margin="20,10">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Viewbox Margin="10">
<TextBlock x:Name="CaseNo_TextBlock" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Viewbox>
<Grid Margin="10" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<TextBlock Text="D01 D01-020-0B-21" Grid.Row="0" HorizontalAlignment="Center" />
<!--<md:PackIcon Kind="ArrowBottom" Grid.Row="1" HorizontalAlignment="Center" Width="45" Height="45" />-->
<TextBlock Text="D09" Grid.Row="2" HorizontalAlignment="Center" />
</Grid>
</Grid>
<TextBlock x:Name="Items_TextBlock" FontSize="28" HorizontalAlignment="Center" Margin="5" Grid.Row="1" />
</Grid>
</md:Card>
</rx:ReactiveUserControl>
and code behind:
public partial class JobLineView : ReactiveUserControl<JobLineViewModel>
{
public JobLineView()
{
InitializeComponent();
this.WhenActivated(d =>
{
this.OneWayBind(ViewModel, vm => vm.JobLine, v => v.CaseNo_TextBlock.Text, jl=>jl.CaseNo)
.DisposeWith(d);
/* this.OneWayBind(ViewModel, vm => vm.JobLine.Status, v => v.CaseNo_TextBlock.Foreground, status=> JobLineStatusToBrushConverter.Instance.Convert(status,null,null,null))
.DisposeWith(d);
this.OneWayBind(ViewModel, vm => vm.JobLine, v => v.Items_TextBlock.Text, jl=> JobLineToItemsStringConverter.Instance.Convert(jl, null,null,null))
.DisposeWith(d);*/
});
}
}
I will be gratefull for any idea. This one is really tricky and I dont know how to solve it.
I am also adding screenshot of the managed memory:
Thanks
-----EDIT
I did strip whole View of everything, to dodge potential issue in MaterialDesign:
But the issue persist, gotta be something with ReactiveUI, but what...
Also this is JobLine class, which is getting passed to the VM:
public class JobLine : ReactiveObject
{
[Reactive]
public string CaseNo { get; set; }
[Reactive]
public decimal? CreatedBy { get; set; }
[Reactive]
public DateTime? CreatedDate { get; set; }
[Reactive]
public string FromInventory { get; set; }
[Reactive]
public string FromLocator { get; set; }
[Reactive]
public decimal Id { get; set; }
[Reactive]
public decimal? JobHeaderId { get; set; }
[Reactive]
public decimal? MachineId { get; set; }
[Reactive]
public decimal? PickingOrder { get; set; }
[Reactive]
public decimal? Printed { get; set; }
[Reactive]
public decimal? RoutingId { get; set; }
[Reactive]
public decimal? SourceLineId { get; set; }
[Reactive]
public decimal? Status { get; set; }
[Reactive]
public string ToInventory { get; set; }
[Reactive]
public string ToLocator { get; set; }
[Reactive]
public decimal? UpdatedBy { get; set; }
[Reactive]
public DateTime? UpdatedDate { get; set; }
[Reactive]
public decimal? Valid { get; set; }
[Reactive]
public string WindowsUser { get; set; }
}
After eliminating every factor possible (stripped the view and view model empty of any binding, or material design stuff (icon) etc) the issue still persist. Something is keeping the View alive in memory, altogether with the ViewModel. While not being in the visual tree anymore.
Any ideas are welcome.
The bug was reported and fixed here in library repository:
https://github.com/reactiveui/ReactiveUI/issues/3091
In my application I have a ListBox and a DataGrid.
I'm trying to bind the DataGrid to an ObservableCollection which is a property of the returned SelectedItem from the ListBox - this doesn't work and I don't understand why. Output console doesn't print any errors.
The ObservableCollection is of type ReportItem, and it can contain instances of TextReportItem, which inherits from ReportItem.
XAML:
<ListBox x:Name="listBox" HorizontalAlignment="Left" Margin="10,10,0,36.667" Width="119" ItemsSource="{Binding ReportItems}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel HorizontalAlignment="Left" Height="274" Margin="134,10,0,0" VerticalAlignment="Top" Width="375" >
<StackPanel.Resources>
<Style x:Key="ControlBaseStyle" TargetType="{x:Type Control}">
<Setter Property="Margin" Value="0, 10, 0, 0" />
</Style>
</StackPanel.Resources>
<DataGrid Height="190" VerticalAlignment="Bottom" DataContext="{Binding ElementName=listBox, Path=SelectedItem.TItems}" />
</StackPanel>
ViewModel:
public class MainViewModel
{
public ObservableCollection<ReportItem> ReportItems { get; set; }
public object SelectedReportItem { get; set; }
public MainViewModel()
{
ReportItems = new ObservableCollection<ReportItem>();
ReportItems.Add(Example);
}
// line below is for debugging purposes
public TextReportItem Example = new TextReportItem() { Name = "ti1", DataFile = "ti1.txt"};
}
ReportItem:
public class ReportItem
{
public int Id { get; set; }
public string Name { get; set; }
public string DataFile { get; set; }
}
TextReportItem and TextParcel:
public class TextReportItem : ReportItem
{
public ObservableCollection<TextParcel> TItems { get; set; }
public TextReportItem()
{
TItems = new ObservableCollection<TextParcel>();
}
}
public class TextParcel
{
public char Delimiter { get; set; }
public string LineExp { get; set; }
public string Result { get; set; }
public string IgnoreLine { get; set; }
public int DesiredResultIndexInLine { get; set; }
}
I think the mere DataContext doesn't tell the DataGrid what it has to show. You have to give it an ItemsSource. Maybe you could try something like that:
<DataGrid
DataContext="{Binding ElementName=listBox, Path=SelectedItem}"
ItemsSource="{Binding TItems}" />
I believe that the DataContext of a DataGrid expects an IEnumerable, and not a single instance of an object. When you set the source to a single instance of a ReportItem, you're not passing it anything that it can iterate to construct it's rows.
If you make the necessary changes and give that a yank, you should be golden :)
you can use select index change method instead
protected void GridView_SelectedIndexChanged(object sender, EventArgs e){
string value = null;
value = GridView1.SelectedRow.Cells(2).Text.ToString();
}
This is my Employee and Company class
public class Employee
{
public int ID { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public Employee()
{
}
public Employee(int id, string name, string address)
{
this.ID = id;
this.Name = name;
this.Address = address;
}
}
public class Company
{
public string Name { get; set; }
public List<Employee> Employees { get; set; }
public Employee SelectedEmployee { get; set; }
public Company()
{
this.Name = "Test Technologies";
this.Employees = new List<Employee>();
this.Employees.Add(new Employee(1, "Prabodha", "Kottawa"));
this.Employees.Add(new Employee(2, "Prasad", "Rukmalgama"));
this.Employees.Add(new Employee(3, "Nisitha", "Nugegoda"));
this.Employees.Add(new Employee(4, "Danesh", "Kesbawa"));
this.Employees.Add(new Employee(5, "Jeewan", "Pannipitiya"));
this.SelectedEmployee = this.Employees.First();
}
}
And I have a DataTemplate called EmployeeCompanyDetails
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DataTemplate x:Key="EmployeeCompanyDetails">
<Grid>
<StackPanel Grid.Column="0" Background="Azure">
<TextBlock Text="~~ Employee Details ~~" />
<TextBlock x:Name="txtSelectedDetails" Text="{Binding View.CurrentCell.Item.ID, ElementName=DataGrid}" FontSize="20" FontWeight="SemiBold"/>
</StackPanel>
</Grid>
</DataTemplate>
And here is my MainWindow.xaml file
<Window x:Class="DataTemplateTEst.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:local="clr-namespace:DataTemplateTEst">
<Window.DataContext>
<local:Company/>
</Window.DataContext>
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/DataTemplateTEst;component/DataTemplates/EmployeeDetails.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0">
<TextBlock Text="{Binding SelectedEmployee.Name}"/>
<DataGrid ItemsSource="{Binding Employees}" SelectedItem="{Binding SelectedEmployee,Mode=TwoWay}"/>
</StackPanel>
<ContentControl Grid.Column="1" DataContext="{Binding}" ContentTemplate="{StaticResource EmployeeCompanyDetails}"/>
</Grid>
What I want is I want to show the name of the selected Employee in the txtSelectedDetails(TextBlock in the DataTemplate). Since following code segment is wrong this is not working.
<TextBlock x:Name="txtSelectedDetails" Text="{Binding View.CurrentCell.Item.ID, ElementName=DataGrid}" FontSize="20" FontWeight="SemiBold"/>
I'm new to C# and I'm trying to bind a function in each item of my collection to a button for that item. My collection is a List<AssessmentItem>, where each AssessmentItem is the following:
public class AssessmentItem
{
public string Label { get; set; }
public string Explanation { get; set; }
public string ResourceURL { get; set; }
public BitmapImage Icon { get; set; }
public RunFixer Fixer { get; set; }
}
public RunFixer Fixer is the delegate I want to bind to the button for that particular AssessmentItem. Here is the DataTemplate I'm using to accomplish my plans:
<DataTemplate x:Key="AssessmentListTemplate">
<Grid Margin="0,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Label}" FontSize="16" VerticalAlignment="Center" Grid.Column="0" FontWeight="Bold" Margin="15,0,0,0"/>
<Button Grid.Column="2" Margin="0,0,10,0">
<Image Source="{Binding Icon}" Width="64" Height="64"/>
</Button>
</Grid>
</DataTemplate>
How do I bind the <Button>'s Click handler to my RunFixer delegate? I tried {Binding Fixer}, which didn't work. I also changed Fixer to a MouseButtonEventHandler, but that didn't work either.
Thank you for your time looking at this! I don't mind being educated.
Additions
The RunFixer delegate is declared with
public delegate void RunFixer();
Final Code
For my personal documentation and for other's satisfaction, I'm posting the result that worked well for me:
public class AssessmentItem
{
public string Label { get; set; }
public string Explanation { get; set; }
public string ResourceURL { get; set; }
public BitmapImage Icon { get; set; }
public RunFixer Fixer { get; set; }
DelegateCommand _fixerCommand = null;
public ICommand FixerCommand
{
get
{
if (_fixerCommand == null)
{
_fixerCommand = new DelegateCommand(() => Fixer());
}
return _fixerCommand;
}
}
}
And in the DataTemplate:
<DataTemplate x:Key="AssessmentListTemplate">
<Grid Margin="0,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Label}" FontSize="16" VerticalAlignment="Center" Grid.Column="0" FontWeight="Bold" Margin="15,0,0,0"/>
<Button Grid.Column="2" Margin="0,0,10,0" Command="{Binding FixerCommand}">
<Image Source="{Binding Icon}" Width="64" Height="64"/>
</Button>
</Grid>
</DataTemplate>
Hope this helps!
You can't bind a function to a button. But you can bind command object to a button's Command property. In order to do this you need to modify your class:
public class AssessmentItem
{
public string Label { get; set; }
public string Explanation { get; set; }
public string ResourceURL { get; set; }
public BitmapImage Icon { get; set; }
public RunFixer Fixer { get; set; }
ICommand _fixerCommand = new UICommand();
public ICommand FixerCommand {
get
{
_fixerCommand = _fixerCommand ?? new DelegateCommand<object>((o)=>
{var f = Fixer;
if(f != null) f();});
return _fixerCommand;}
}
}
I'm using DelegateCommand class which is a part of Prism library which can be downloaded here
Then you're modifying your data template to bind to this FixerCommand property
<Button Grid.Column="2" Margin="0,0,10,0" Command ="{Binding FixerCommand}">
<Image Source="{Binding Icon}" Width="64" Height="64"/>
</Button>
You can't bind the "Click" event of a button because it is not a dependency property (in this case it is a routed event). Luckily, WPF gives us the "Command" property (which is a dependency property) for a button!
Your binding will look like:
Command="{Binding RunFixerCommand}"
Your data object will expose an ICommand property which will return a command object that calls "RunFixer". A great example of a reusable and easy to use generic command class can be found in this blog post.
Sample (in your AssessmentItem class):
public ICommand RunFixerCommand {get; private set;}
public AssessmentItem()
{
RunFixerCommand = new DelegateCommand((p) => RunFixer());
}
I need help in binding data especially if the root datasource object has many subclasses and those subclasses has a subclass too. Here is my DataModel:
public class NowShowingMovies
{
public ObservableCollection<Movie> MovieCollection { get; set; }
public string Status { get; set; }
public string Total{ get; set; }
}
public class Movie
{
public string Id {get;set;}
public string Title {get;set}
public UserRating Rating {get;set;}
}
public class UserRating
{
public string UserRatingURL {get;set;}
}
And my XAML code is:
<GridView ItemsSource="{Binding MovieCollection}"
<GridView.ItemTemplate>
<DataTemplate>
<Grid>
<Border Background="White">
<TexBlock Text="{Binding Title}"/>
</Border>
<Grid Background="Black" Margin="0,0,0,0" Opacity="0.75" x:Name="grid_rating"/>
<Image Source ="{Binding Path=MovieCollection.Rating.UserRatingURL}" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
Problem is I can't make it work. UserRatingURL is not showing. I even changed it to
<Image Source ="{Binding Path=MovieCollection[0].Rating.UserRatingURL}" />
and still, no luck. What am I doing wrong? Thanks in advance!
Try to remove MovieCollection in your path.
Image Source ="{Binding Path=Rating.UserRatingURL}"