I need to print a complex document with paging from silverlight. Ihave found a good project from http://silverlightreporting.codeplex.com/. Playing with this example, i have found, that more complex templates works not correctly:
I have add a ChildNames property:
public class EmployeeReviewReportItem
{
public string LastName { get; set; }
public string FirstName { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
public int PerformanceRating { get; set; }
public decimal Salary { get; set; }
public decimal Bonus { get; set; }
public string ReviewComments { get; set; }
public string[] ChildNames { set; get; }
}
in ReportData.cs set value for this property:
ChildNames = new string[] { firstNames.Random(), firstNames.Random(), firstNames.Random() }
and then in MainPage.xaml a new ListBox to show this prperty:
...
<TextBlock Grid.Row="2"
Grid.ColumnSpan="4"
TextWrapping="Wrap"
Text="{Binding ReviewComments}" />
<ListBox Grid.Row="3" Grid.ColumnSpan="4" ItemsSource="{Binding ChildNames}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Width="300"
Height="auto"
VerticalAlignment="Top"
Text="{Binding .}"
TextWrapping="Wrap" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
...
ListBox will be rendered without content.
How i can get Child names printed?
Does {Binding .} work? I've never seen it (of course that doesn't mean it isn't correct). I would just use {Binding} instead. If that doesn't work then you can try changing string[] to ObservableCollection<string> and also make the binding a twoway binding: ItemsSource="{Binding ChildNames, Mode=TwoWay}".
Without seeing the complete source code, I can't really help much more than this.
Related
In Catel.MVVM:
In the case when adding a new Customer where a property Id1 is still null, the IdDocumentView would have an IdDocumentViewModel context when there is a match on a constructor (one that does not have an IdDocument parameter) leading to a ViewModel with no Model. Is there a standard way of working with this scenario, maybe by setting customer.Id1 to an instance of IdDocument with default values so that the View has a context allowing for binding to update the values of the IdDocument instance?
Structure:
MainView : Catel.Windows.Controls.UserControl
_|--CustomerWindow : Catel.Windows.Window
___|--IdDocumentView : Catel.Windows.Controls.UserControl
Model Classes:
public class Customer : Entity
{
[DomainSignature]
public string Code { get; set; }
public Gender Gender { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string MiddleName { get; set; }
public DateTime DateOfBirth { get; set; }
public Lookup PlaceOfBirth { get; set; }
public string MobileNumber { get; set; }
public string Email { get; set; }
public ICollection<CustomerAddress> Addresses { get; set; }
public Lookup Occupation { get; set; }
public IdDocument Id1 { get; set; }
public IdDocument Id2 { get; set; }
}
public class IdDocument : Entity
{
[DomainSignature]
public Lookup IdType { get; set; }
[DomainSignature]
public string IdCode { get; set; }
[DomainSignature]
public DateTime IdExpiry { get; set; }
}
In CustomerView
<DockPanel HorizontalAlignment="Stretch" Grid.ColumnSpan="2">
<GroupBox Header="ID 1" DockPanel.Dock="Top" Margin="0">
<local:IdDocumentView DataContext="{Binding Id1}" HorizontalAlignment="Stretch" />
</GroupBox>
</DockPanel>
<orccontrols:EmptyColumn />
<DockPanel HorizontalAlignment="Stretch" Grid.ColumnSpan="2">
<GroupBox Header="ID 2" DockPanel.Dock="Top" Margin="0">
<local:IdDocumentView DataContext="{Binding Id2}" HorizontalAlignment="Stretch" />
</GroupBox>
</DockPanel>
IdDocumentView
<catel:UserControl x:Class="CTT.MTS.Views.IdDocumentView"
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:CTT.MTS.Views"
xmlns:catel="http://schemas.catelproject.com"
xmlns:orccontrols="http://schemas.wildgums.com/orc/controls"
xmlns:app="clr-namespace:CTT.MTS.Model"
xmlns:controls="clr-namespace:CTT.MTS.Controls"
mc:Ignorable="d"
d:DesignHeight="800" d:DesignWidth="800">
<orccontrols:StackGrid>
<!-- Row definitions -->
<orccontrols:StackGrid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="40" />
<RowDefinition Height="40" />
</orccontrols:StackGrid.RowDefinitions>
<!-- Column definitions -->
<orccontrols:StackGrid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</orccontrols:StackGrid.ColumnDefinitions>
<Label Content="Type" />
<ComboBox ShouldPreserveUserEnteredPrefix="False" IsEditable="False" ItemsSource="{Binding IdTypes}"
DisplayMemberPath="Value" SelectedValuePath="Value" SelectedValue="{Binding IdTypeText}" Width="100"
HorizontalAlignment="Left">
</ComboBox>
<Label Content="Code" />
<TextBox Text="{Binding IdCode}" Width="100" HorizontalAlignment="Left"></TextBox>
<Label Content="Expiry" />
<orccontrols:DatePicker Width="120" HorizontalAlignment="Left" Margin="0" Height="40"
Value="{Binding IdExpiry, ValidatesOnDataErrors=True, NotifyOnValidationError=True}">
</orccontrols:DatePicker>
</orccontrols:StackGrid>
</catel:UserControl>
in MainViewModel in a command method for a Button click
await uiVisualizerService.ShowAsync<CustomerViewModel>(new Customer
{
DateOfBirth = new DateTime(1981, 8, 8),
Gender = Gender.Male,
FirstName = "Muhammad",
Id1 = new IdDocument { IdType = idType, IdCode = "1111", IdExpiry = DateTime.Now.AddYears(-1) },
//Id2 = new IdDocument(),
Addresses = new List<CustomerAddress>(new[]
{new CustomerAddress {Address = address, AddressType = addressType, IsCurrent = true}})
});
notice Id2's initialization is commented. If left like that null IdDocumentView would have no link to an IdDocument model
IdDocumentViewModel's constructors
public IdDocumentViewModel(ILookupService lookupService)
{
Argument.IsNotNull(() => lookupService);
this.lookupService = lookupService;
IdTypes = lookupService.IdTypes;
}
public IdDocumentViewModel(IdDocument idDocument, ILookupService lookupService) :this(lookupService)
{
IdDocument = idDocument;
IdTypeText = idDocument.IdType?.Value ?? "";
}
Note that I added the first less arguments constructor after noticing the constructor with an IdDocument parameter not being called for Customer.Id1 when it is null.
Any ideas?
You assumption is correct that:
Catel will first try to construct a vm with model injection
If that's not possible, it will use the one with the most parameters it can construct
If that's not possible, no VM will be constructed
In such cases, I normally pass in a temporary (new) model without an id. This way, the "child vm" knows it's in create state instead of edit.
I have two related entities:
public class Event
{
public string ID { get; set; }
public DateTime EventDate { get; set; }
public string EventData { get; set; }
public string DocID1 { get; set; }
public int DocID2 { get; set; }
public virtual Document Document1 { get; set; }
public virtual Document Document2 { get; set; }
}
public class Document
{
public string ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Number { get; set; }
}
Also created List to display data in WPF:
private ObservableCollection<Event> eventList;
public ObservableCollection<Event> EventList
{
get { return eventList; }
set
{
if (value != eventList)
{
eventList = value;
}
RaisePropertyChanged(nameof(EventList));
}
}
data for my EventList is taken from entity Event:
var query = DBContext.Events.Select(x => x).AsQueryable();
EventList = query.ToList();
What I need is how to set GridControl Column "colFirstName" value to be equal "Document1.FirstName" if DocID1 is not null and "Document2.FirstName" if DocID2 is not null. My XAML code for GridControl is below, could You help how to do it in Xaml, not in ViewModel, or if there is no way to do it in Xaml, what is the best way to do it in ViewModel.
<dxg:GridControl AutoPopulateColumns="False"
ItemsSource="{Binding EventList, UpdateSourceTrigger=PropertyChanged}">
<dxg:GridControl.Columns>
<dxg:GridColumn
x:Name="colEventData"
Width="120"
FieldName="EventData"
Header =" Event data"
Visible="True" >
</dxg:GridColumn>
<dxg:GridColumn
x:Name="colFirsnName"
Width="120"
FieldName="Document1.FirstName"
Header="First Name"
Visible="True"
VisibleIndex="1" />
</dxg:GridControl.Columns>
</dxg:GridControl>
You can use the UnboundExpression property to create a column with a custom expression. For example, to conditionally show values from different properties, use the Iif function:
<dxg:GridColumn FieldName="CustomColumn" x:Name="colFirsnName"
UnboundExpression="Iif(IsNullOrEmpty([DocID1]), [Document2.FirstName], [Document1.FirstName])"
UnboundType="String"/>
This kind of logic should be implemented in the model or view model class. Remember that XAML is only a markup language.
Just create another property that returns the first match and bind to this one. If your entity classes are auto-generated, you could create a new partial class:
public partial class Event
{
public string DocName
{
get
{
if (Document1 != null)
return Document1.FirstName;
if (Document2 != null)
return Document1.LastName;
return null;
}
}
}
<dxg:GridColumn
x:Name="colFirsnName"
Width="120"
FieldName="DocName"
Header="First Name"
Visible="True"
VisibleIndex="1" IsReadOnly="true" />
I have a ListView which is populated with a collection called Files(ObservableCollection FileViewModel ), also I have another SelectedFiles(List Guid ) which hold the selected files id in it, how can I bind this to the UI to show the selected files with checkbox control.
Xaml:
<ListView Grid.Column="0" Grid.Row="2" Name="lstSourceFiles" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<ListView.ItemTemplate>
<DataTemplate>
<WrapPanel>
<CheckBox></CheckBox>
<TextBlock Text="{Binding Name}"></TextBlock>
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Code:
public List<Guid> SelectedSourceFiles { get; set; }
public ObservableCollection<FileViewModel> Files { get; set; }
public class FileViewModel
{
public Guid Id { get; set; }
public string Name { get; set; }
}
public partial class MainWindow : Window
{
public List<Guid> SelectedSourceFiles { get; set; }
public MainWindow()
{
AddHandler(TreeViewItem.SelectedEvent, new RoutedEventHandler(TreeItemSelected), true);
}
private void TreeItemSelected(object sender, RoutedEventArgs e)
{
var item = e.OriginalSource as TreeViewItem;
if (item == null)
{ return; }
var folder = item.DataContext as FolderViewModel;
if (folder == null)
{ return; }
if (!folder.IsFilesLoaded)
{
FileManager.LoadFiles(folder);
}
lstSourceFiles.ItemsSource = folder.Files;
}
}
The easiest way would be to add an "IsSelected" property to the view model:
public class FileViewModel
{
public Guid Id { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
Loop through and set the property:
foreach (var file in folder.Files)
file.IsSelected = (SelectedSourceFiles.Contains(file.Guid);
And then of course bind to it:
<CheckBox IsChecked="{Binding IsSelected}" />
An alternate to the above would be to bind to the GUID and use IValueConverter that checks against the the selected list.
I could not load images of thumbnail youtube.
Class file:
public class YoutubeVideo
{
public string id { get; set; }
public string title { get; set; }
public DateTime pubdate { get; set; }
public Uri youtubelink { get; set; }
public Uri videolink { get; set; }
public Uri thumbnail { get; set; }
}
On mainpage.xaml:
<DataTemplate>
<StackPanel>
<Image Source="{Binding thumbnail}"></Image>
<TextBlock Text="{Binding title}" FontSize="10" Foreground="#cc181e" TextWrapping="Wrap"></TextBlock>
<Grid>
</Grid>
</StackPanel>
</DataTemplate>
It just show title.
After looking at your code here is the solution
change
video.id = item.Id.Remove(0, 27);
to
video.id = item.Id.Substring(item.Id.LastIndexOf("/") + 1);
that should produce the correct id of the video
the id of the video is the last few chars
eg
http://gdata.youtube.com/feeds/base/videos/_OBlgSz8sSM
I have two classes,
public class BookItem
{
public string BookID { get; set; }
public string ItemID { get; set; }
public Item Item { get; set; }
public ItemType Type { get; set; }
public string ParentID { get; set; }
public string BoxID { get; set; }
public string StyleID { get; set; }
public string NotesID { get; set; }
public string Code_XAML { get; set; }
public string Description_XAML { get; set; }
public CompositeCollection SubItems { get; set; }
}
public class Item : ClaunchBaseClass
{
public string ItemID { get; set; }
public int Type { get; set; }
public string Code { get; set; }
public string Description { get; set; }
private BookList _books = new BookList();
public BookList Books { get {return _books;} set { _books = value; }}
}
and I've created the following XAML:
<pre>
<TreeView Name="tvList" Grid.Row="2" MouseDoubleClick="tvList_MouseDoubleClick">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="x:Type j:BookItem" ItemsSource="{Binding SubMenu}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Item.Code}" Grid.Column="0" />
<TextBlock Text="{Binding Item.Description}" Grid.Column="1"/>
</Grid>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<code>
This XAML binds the treeview items to the collection of book items and displays the Item subclass's Description and Code, the treeview populates and displays correctly but now I want to sort the treeview on either Item.Code or Item.Description and have tried the following with no results:
<pre>
var bookItemsSort = CollectionViewSource.GetDefaultView(_bookItemList) as ListCollectionView;
tvList.ItemsSource = _bookItemList; //bind the book items to the treeview
bookItemsSort.SortDescriptions.Clear();
bookItemsSort.SortDescriptions.Add(new SortDescription(sort, Ascending));
<code>
I've had this code work correctly for other treeviews so I can only guess it is a problem with binding to a subclass.
While the answers here provided partial answers to my question, none of them gave the answer that I needed.
The most sensible solution for this problem was to write my own object comparer for this object type and sort the underlying list and then re-bind the new list to the treeview. This allowed for comparing sublasses at any nested level which I couldn't make work any other way :)
You need to get the default view for each sub-list, and apply a CollectionViewSource sorting to it. The code you posted only affects the top level items.
Bind your TreeView.ItemsSource to the DefaultView. SortDescriptions will not change your DataList, only the View of it.
tvList.ItemsSource = bookItemsSort;
See Bea Stollnitz blog: How can I sort a hierarchy?