I'm new to WPF and am using the Syncfusion Framework. I want to use the DataTreeControl to display a hierarchy of data which will be loaded and updated in a reoccuring interval. But for some reason it doesn't display the data.
Here's a snipped from my MainWindow.xaml
<syncfusion:TabItemExt Name="_tabItemTipps" Header="Tipps">
<syncfusion:GridTreeControl Name="_treeGrid"
BorderBrush="LightGray"
BorderThickness="0,0.5,0,0"
EnableHotRowMarker="False"
EnableNodeSelection="True"
ExpandStateAtStartUp="AllNodesExpanded"
ReadOnly="True"
SupportNodeImages="True"
VisualStyle="Metro"
ItemsSource="SoccerMarkets"
>
<!-- Code for GridTreeControl Columns -->
<syncfusion:GridTreeControl.Columns>
<syncfusion:GridTreeColumn HeaderText="Nation" MappingName="{Binding RoughCat}"></syncfusion:GridTreeColumn>
</syncfusion:GridTreeControl.Columns>
</syncfusion:GridTreeControl>
This the snippet from MainWindow.xaml.cs where the DataContext is set:
public MainWindow()
{
DataContext = this;
InitializeComponent();
SkinStorage.SetVisualStyle(_tabControl, "Metro");
_settingsVM = new AppSettingsVM();
_txtBetdaqUser.DataContext = _settingsVM;
_chkSystemActive.DataContext = _settingsVM;
_chkInSimulationMode.DataContext = _settingsVM;
_mechanic = new TippMechanic(_settingsVM);
_soccerMarketsVM = new SoccerMarketVM();
Task[] tasks = new Task[1];
tasks[0] = Task.Factory.StartNew(async () => await _mechanic.Init());// _mechanic.Init();
Task.WaitAll(tasks);
_soccerMarketsVM.SoccerMarkets = _mechanic.SoccerMarketManager.SoccerMarkets;
_treeGrid.DataContext = _soccerMarketsVM.SoccerMarkets;
}
My ViewModel (_soccerMarketsVM) is defined this way:
class SoccerMarketVM : ObservableObject
{
private ObservableCollection<SoccerMarket> _soccerMarkets;
public ObservableCollection<SoccerMarket> SoccerMarkets
{
get { return _soccerMarkets; }
set
{
if(_soccerMarkets != null)
_soccerMarkets.CollectionChanged -= _soccerMarkets_CollectionChanged;
_soccerMarkets = value;
_soccerMarkets.CollectionChanged += _soccerMarkets_CollectionChanged;
}
}
public SoccerMarketVM()
{
//_soccerMarkets = new ObservableCollection<SoccerMarket>();
//_soccerMarkets.CollectionChanged += _soccerMarkets_CollectionChanged;
}
void _soccerMarkets_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
Console.WriteLine(e.Action.ToString());
}
}
The Events for CollectionChanged are fired and I get the Console.Writeline output.
Does anyone see's something wrong here?
In GridTreeControl, you can populate the data using different ways. In your code snippet, ItemsSource defined without specifying the Binding keyword and the MappingName is defined with Binding keyword. But for itemssource, you need to specify binding and for mapping name, you can directly assign property name without specifying binding. Please refer the below UG link of data population in GridTreeControl,
Link:
http://help.syncfusion.com/ug/wpf/index.html#!Documents/addingthegridtreecontroltoawpfapplication.htm
Elavarasan M – Syncfusion Software.
Related
I'm currently developping a new soft which analyze a lot of data on Revit.
I have my WPF View, my ViewModel and a long methode.
init.cs:
IExternalEventHandler handlerEvent = new FamilyAnalysis();
var familyAnalysisEvent = ExternalEvent.Create(handlerEvent);
Gui = new AnalysisView(familyAnalysisEvent);
Gui.Show();
AnalysisView.xaml.cs:
public AnalysisView(ExternalEvent externalEvent)
{
InitializeComponent();
Windows.SetLocation(this);
Language = System.Windows.Markup.XmlLanguage.GetLanguage(System.Threading.Thread.CurrentThread.CurrentCulture.Name);
DataContext = new AnalysisViewModel(externalEvent, this);
}
AnalysisViewModel.cs:
public ICommand StartAnalysisCommand
{
get
{
return _startAnalysisCommand ?? (_startAnalysisCommand = new RelayCommand(() =>
{
//Some check before then..
_externalEvent.Raise();
}));
}
}
during the _externalEvent.Raise() I would like to have a loading form updating the state of the methode.
I tried to search about dispatcher but I'm not sure how to do that and all my try didn't worked. The loading screen pop but the value are not getting updated.
Any advice ?
I have rather interesting problem. I have a DataGrid in wpf that looks like:
<DataGrid ItemsSource="{Binding View, IsAsync=True, Mode = TwoWay}"
AutoGenerateColumns="False"
EnableColumnVirtualization="True"
EnableRowVirtualization="True"
VirtualizingStackPanel.VirtualizationMode="Standard"
VirtualizingStackPanel.IsVirtualizing="True">
COLUMNS
</DataGrid>
On data in that grid I am performing crud operations, but it seems I cannot refresh view after Add or Delete operation, it works perfectly when I Update record or filter it.
Simple C# ops I tried in view model.
Read:
public CommendationViewModel()
{
this._catalog = new CatalogContexct();
this._commendations = this._catalog.Commendations.ToList();
var commendation = new ListCollectionView(this._commendations);
this.CommendationView = CollectionViewSource.GetDefaultView(commendation);
this.AddCommand = new RelyCommand(AddEntity, param => this._canExecute);
this.EditCommand = new RelyCommand(EditEntity, param => this._canExecute);
this.UpdateCommand = new RelyCommand(UpdateEntity, param => this._canExecute);
this.RemoveCommand = new RelyCommand(RemoveEntity, param => this._canExecute);
this.NameCommand = new RelyCommand(Filter, param => this._canExecute);
this.CancelCommand = new RelyCommand(Cancel, param => this._canExecute);
}
And add:
public void AddEntity(object obj)
{
if(string.IsNullOrEmpty(this.Name))
{
MessageBox.Show("Brak nazwy do dodania");
return;
}
var commendation = new Commendation() { Name = this.Name };
this._catalog.Commendations.Add(commendation);
this._catalog.SaveChanges();
var commendationRefresh = new ListCollectionView(this._catalog.Commendations.ToList());
this.CommendationView = CollectionViewSource.GetDefaultView(commendationRefresh);
this.CommendationView.Refresh();
MessageBox.Show("Nowe źródło polecenia zostało dodane");
}
As you see I tried to Refresh view in add command but it did not work. Any suggestions?
Bind to CommendationView:
<DataGrid ItemsSource="{Binding CommendationView}" ...
...and make sure that the setter of this property raises the PropertyChanged event:
private ICollectionView _commendationView;
public ICollectionView CommendationView
{
get { return _commendationView; }
set { _commendationView = value; NotifyPropertyChanged(); }
}
The view model class must implement the INotifyPropertyChanged interface for this to work: https://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged(v=vs.110).aspx
I'm building an MVVM Light WPF app using Visual Studio 2015. The app needs to display some SQL Server Reporting Services reports locally.
The following two solutions exist:
Using MS ReportViewer in WPF
Walkthrough: Using ReportViewer in a WPF Application
Though the first is MVVM, it's mixing UI with the view model. The second is pure code-behind.
Here's what the first example suggests:
WindowsFormsHost windowsFormsHost = new WindowsFormsHost();
reportViewer = new ReportViewer();
windowsFormsHost.Child = reportViewer;
this.Viewer = windowsFormsHost
Note that ReportViewer is a UI control. The second solution uses a code-behind file:
private void ReportViewer_Load(object sender, EventArgs e)
{
//...
}
Is there a way to embed a local SSRS report into a WPF app and follow good MVVM practices? Thank you.
Update: No need to be fanatical! If some code-behind is needed, I'm okay with it.
We use a view to select the report from a ComboBox and a button to run it. In the viewmodel, we have the reports' ComboBox bound to an ObservableCollection of report names and IDs. We then employ the MVVM Light Toolkit's Messaging class to send/receive "messages." Note that the base viewmodel, MyAppViewModelBase, inherits from Light Toolkit's ViewModelBase, which has the RaisePropertyChanged() defined.
Also note that we could pass the selected report's VM instead of the view's VM; that would be more efficient but will require modifications to this code. Then we'd use a base class for all the report VMs and a pattern-matching switch in the code-behind to select which report to run.
Here's the pertinent code for the viewmodel:
using GalaSoft.MvvmLight.Messaging;
public class ReportsViewModel : MyAppViewModelBase
{
public ReportsViewModel()
{
// Register a listener that receives the enum of the
// report that's ready. The message it receives has
// name "SsrsReportReady" with handler SsrsReportReady.
Messenger.Default.Register<Constants.Report>(this, "SsrsReportReady", SsrsReportReady);
// Other logic...
}
// Bound to a button to run the selected report
public ICommand RunReportRelayCommand =>
new RelayCommand(RunReport);
// Backing field for the selected report.
private ReportViewModel _selectedReportVm;
public ReportViewModel SelectedReportVm
{
get { return _selectedReportVm; }
set
{
if (Equals(value, _selectedReportVm)) return;
_selectedReportVm = value;
// Built-in method from Light Toolkit to
// handle INotifyPropertyChanged
RaisePropertyChanged();
}
}
private void RunReport()
{
// Send a message called "RunSSRSReport" with this VM attached as its data.
Messenger.Default.Send(this, "RunSSRSReport");
}
// Handler for report-ready
private void SsrsReportReady(Constants.Report obj)
{
ShowReport = true;
IsRunReportButtonEnabled = true;
RunReportButtonContent = Constants.BtnGenerateReport;
// View uses Material Design's Expander control.
// We expand/collapse sections of the view.
ExpandReport = true;
ExpandParameters = false;
}
}
In the code-behind of the view:
using GalaSoft.MvvmLight.Messaging;
public partial class ReportsView : UserControl
{
public ReportsView()
{
InitializeComponent();
// Register a listener for the "RunSSRSReport"
// message, called from our viewmodel. Its
// handler is RunSsrsReport and its data type
// is ReportsViewModel.
Messenger.Default.Register<ReportsViewModel>(this, "RunSSRSReport", RunSsrsReport);
DataContext = new ReportsViewModel();
}
// Handler to run the selected report.
private void RunSsrsReport(ReportsViewModel obj)
{
// Basic validation
if (obj.SelectedReportVm == null || obj.SelectedReportVm.Id.Equals(-1))
{
return;
}
// Ugly switch to run the correct report.
// It can be re-written with pattern matching.
switch (obj.SelectedReportVm.Id)
{
case (int)Constants.Report.ReportA:
RunReportA(obj);
break;
case (int)Constants.Report.ReportB:
RunReportB(obj);
break;
// other reports....
}
}
// Run the report using dataset and tableadapter.
// Modify to use your code for running the report.
private void RunReportA(ReportsViewModel reportsViewModel)
{
var dataSet = new ReportADataSet();
dataSet.BeginInit();
// We reference the ReportViewer control in XAML.
ReportViewer.ProcessingMode = ProcessingMode.Local;
ReportViewer.LocalReport.ShowDetailedSubreportMessages = true;
ReportViewer.LocalReport.DataSources.Clear();
var dataSource = new ReportDataSource
{
Name = "ReportA_DS",
Value = dataSet.uspReportA // Uses a stored proc
};
ReportViewer.LocalReport.DataSources.Add(dataSource);
ReportViewer.LocalReport.ReportEmbeddedResource =
"MyApp.Reports.ReportA.rdlc";
dataSet.EndInit();
new reportATableAdapter { ClearBeforeFill = true }
.Fill(dataSet.uspReportA);
// Send message back to viewmodel that the report is ready.
Messenger.Default.Send(Constants.Report.ReportA, "SsrsReportReady");
}
}
The report view has a WindowsFormsHost with name ReportViewer, referenced in above code-behind:
<WindowsFormsHost Width="Auto" Height="500">
<rv:ReportViewer x:Name="ReportViewer" />
</WindowsFormsHost>
I am actually working with this piece of code
using System;
using Xamarin.Forms;
using System.Diagnostics;
namespace CryptoUI
{
public class HomePage : Xamarin.Forms.MasterDetailPage
{
public HomePage()
{
// Set up the Master, i.e. the Menu
Label header = new Label
{
Text = "MENU",
Font = Font.SystemFontOfSize(20, FontAttributes.Bold),
HorizontalOptions = LayoutOptions.Center
};
// create an array of the Page names
string[] myPageNames = {
"Main",
"Page 2",
"Page 3",
};
// Create ListView for the Master page.
ListView listView = new ListView
{
ItemsSource = myPageNames,
};
// The Master page is actually the Menu page for us
this.Master = new ContentPage
{
Title = "Test",
Content = new StackLayout
{
Children =
{
header,
listView
},
}
};
// Define a selected handler for the ListView contained in the Master (ie Menu) Page.
listView.ItemSelected += (sender, args) =>
{
// Set the BindingContext of the detail page.
this.Detail.BindingContext = args.SelectedItem;
string currentPage = this.GetType().Name.ToString();
// This is where you would put your “go to one of the selected pages”
if(listView.SelectedItem.Equals("Main") && !currentPage.Equals("HomePage")){
AsyncPush(new HomePage());
}
else if(listView.SelectedItem.Equals("Page 2") && !currentPage.Equals("SecondPage")){
AsyncPush(new SecondPage());
}
else if(listView.SelectedItem.Equals("Page 3") && !currentPage.Equals("ThirdPage")){
AsyncPush(new ThirdPage());
}
// Show the detail page.
this.IsPresented = false;
};
listView.ItemSelected += (senders, e) => {
if (e.SelectedItem == null) return; // don't do anything if we just de-selected the row
// do something with e.SelectedItem
((ListView)senders).SelectedItem = null; // de-select the row
};
// Set up the Detail, i.e the Home or Main page.
Label myHomeHeader = new Label
{
Text = "Home Page",
HorizontalOptions = LayoutOptions.Center
};
string[] homePageItems = { "Alpha", "Beta", "Gamma" };
ListView myHomeView = new ListView {
ItemsSource = homePageItems,
};
var myHomePage = new ContentPage();
myHomePage.Content = new StackLayout
{
Children =
{
myHomeHeader,
myHomeView
} ,
};
this.Detail = myHomePage;
}
public async void AsyncPush(Page page)
{
await Navigation.PushAsync(page);
}
}
}
This code actually shows an easy FlyOut menu, using the Xamarin Forms technologies.
I am currently trying to understand how I could easily clear the ListView selection after I have selected which page I want to head to!
I found this piece of code on Xamarin's website for devs (http://developer.xamarin.com/guides/cross-platform/xamarin-forms/working-with/listview/);
listView.ItemSelected += (sender, e) => {
if (e.SelectedItem == null) return; // don't do anything if we just de-selected the row
// do something with e.SelectedItem
((ListView)sender).SelectedItem = null; // de-select the row
};
But I can't currently figure out how I should integrate it with my code above there :)
I would like to add to Jason's answer because it misses some vital information. When you set the ListView SelectedItem property to null, it will fire off the ItemSelected event again. So if you do not have a null check, it will throw an exception.
This is what it should look like:
void ItemSelected(object sender, EventArgs args)
{
if (((ListView)sender).SelectedItem == null)
return;
//Do stuff here with the SelectedItem ...
((ListView)sender).SelectedItem = null;
}
You're assigning the ItemSelected handler twice, which is a bad idea. All you should have to do is add this line to your existing ItemSelected handler
((ListView)sender).SelectedItem = null;
I had this same problem but the other solutions did not work for me. Since I needed to pass a custom object to the next page I nullified the selected item reference and used the item tapped reference for my custom object.
listView.ItemTapped += async (sender, e) =>{
await Navigation.PushAsync(new DetailPage(e.Item as CustomObject));
((ListView)sender).SelectedItem = null;
};
ListView.SelectedItem does not have setter (I mean simple Xamarin Android - not Xamarin.Forms). I suggest to use the following code:
private void DeselectEntities()
{
if (this.listView != null && this.listView.CheckedItemPositions != null)
{
this.listView.CheckedItemPositions.Clear();
}
}
I respect all given answers but in an MVVM app you'd better avoid too much code behind. What I usually do is following:
Bind ItemsSource of ListView as usual to an ObservableCollection where T is a CarViewModel in my case
Set SelectionMode="None": This does avoid the selection of SelectedItem on tap
Use EventToCommandBehavior (I use my own implementation; see github.com or use the one from Prism.Forms) to bind ItemTapped event of ListView to my ViewModel command SelectedCarChangedCommand.
In the ViewModel's SelectedCarChangedCommand you'll receive the tabbed item as ItemTappedEventArgs object.
<ListView
x:Name="CarsListView"
ItemsSource="{Binding Cars}"
SelectionMode="None">
<ListView.Behaviors>
<behaviors:EventToCommandBehavior
Command="{Binding SelectedCarChangedCommand}"
EventName="ItemTapped" />
</ListView.Behaviors>
I would like to bind a DataGrid*Column (in this particular case, a DataGridTextBox) to its data in the code-behind. This is because, depending on a CheckBox's IsClicked property, the Column needs to bind to different collections.
Solutions such as this one all point to the following sort of code:
var binding = new Binding("X");
XColumn.Binding = binding;
Now, I've made use of this sort of code in other parts of my program with success, just not with a DataGrid*Column. With the column, however, this is not working as expected, since in fact all the rows of the column are presenting the X-value of the first element of the collection. This is confirmed when I edit any of the cells and all of them are altered, meaning they are all bound to the same single element of the collection, not to the collection as a whole.
Here is the relevant code:
//This is called whenever the CheckBox EqualToResults is clicked
void ControlBindings()
{
//only showing for (.IsChecked == true), but the other case is similar
//and presents the same problems
if (EqualToResults.IsChecked == true)
{
var cable = DataContext as NCable;
//This is the DataGrid object
Coordinates.ItemsSource = cable;
var binding = new Binding("X");
binding.Source = cable.Points;
//XColumn is the DataGridTextColumn
XColumn.Binding = binding;
}
}
Should it be relevant, here's the relevant code for the NCable class.
public class NCable : DependencyObject, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<NPoint> Points;
public static DependencyProperty PointsProperty = DependencyProperty.Register("Points", typeof(ICollectionView), typeof(NCable));
public ICollectionView IPointCollection
{
get { return (ICollectionView)GetValue(PointsProperty); }
set { SetValue(PointsProperty, value); }
}
public NCable(string cableName)
{
Points = new ObservableCollection<NPoint>();
for (int i = 0; i < 11; i++)
Points.Add(new NPoint(1,1));
IPointCollection = CollectionViewSource.GetDefaultView(Points);
}
}
EDIT 13/05: I've seen somewhere that one must also set the ItemsSource of the DataGrid in this case, so I've done that as well (edited the original code), but still to no avail. The entire column is still bound to the first element of the collection.
Figured it out. In this case, the DataGrid.ItemsSource must be defined (as per the edit in the oP), but the binding.Source must be left undefined. Therefore, the functional code-behind is
void ControlBindings()
{
if (EqualToResults.IsChecked == true)
{
var cable = DataContext as NCable;
Coordinates.ItemsSource = cable;
var binding = new Binding("X");
//REMOVE binding.Source = cable.Points;
XColumn.Binding = binding;
}
}