I have been working on as assignment where WPF GUI is genereated at runtime. Runtime generated GUI is consumed by another wpf application. Template generator application allows to create GUI and save it as xml (xaml is actually xml) using XAMLWriter. Consumer application use XAMLReader to add tamplate on GUI. Now i want some sort of binding among controls in generated template.
Requirement : Date on first Datepicker = 2015/01/02 and textbox Text = 1 then date on second datepicker must be 2015/01/03. If textbox text = -1 the date on second date picker must have 2015/01/01.
How i could achieve this at runtime. Nothing needs to hard code as generated template is generated from another application. We have some specific values on Tag property of control which indicates us which three controls are involved and which datepicker is source ,which datepicker is destination and which textbox text needs to used.
Is it possible to use Dynamic data binding? or how this can be accomplished
=> Rename your Xml file to Xaml
<UserControl ...>
<Grid>
<StackPanel Background="Aqua">
<TextBlock Text="{Binding Path=Label}" Width="200" Height="40"/>
</StackPanel>
</Grid>
=> This is the class you will be merging with the code-behind if there is
public class XamlLoadedType:UserControl, IComponentConnector
{
private bool _contentLoaded;
public void InitializeComponent() {
if (_contentLoaded) {
return;
}
_contentLoaded = true;
var resourceLocater = new System.Uri(_uri, System.UriKind.Relative);
Application.LoadComponent(this, resourceLocater);
}
void IComponentConnector.Connect(int connectionId, object target) {
this._contentLoaded = true;
}
string _uri ;
public XamlLoadedType(string uri)
{
_uri = uri;
InitializeComponent();
}
}
=> The main window and it's viewmodel:
<Window ...>
<Grid>
<StackPanel>
<Button Command="{Binding LoadCommand}" Width="100" Height="50">Load</Button>
</StackPanel>
<StackPanel Grid.Row="1">
<ContentControl Content="{Binding LoadedContent}"/>
</StackPanel>
</Grid>
public class MainViewModel:INotifyPropertyChanged
{
public ICommand LoadCommand { get; set; }
object _loadedContent;
public object LoadedContent
{
get { return _loadedContent; }
set {
SetField(ref _loadedContent, value, "LoadedContent");
}
}
public MainViewModel()
{
LoadCommand = new RelayCommand(Load, ()=>true);
}
private void Load()
{
var xamlLoaded = new XamlLoadedType("/WPFApplication1;component/XamlToLoad.xml.xaml");
xamlLoaded.DataContext = new { Label = "HeyDude" };
LoadedContent = xamlLoaded;
}
}
VoilĂ
Related
I am new to wpf format, and ran into a problem at the end of my project.
So let's say I have a top bar, with one textbox and a button.
When the user clicks the button, the user control below this bar should update with the search results from the textbox, and it does, except it does not refresh the UI, only the data storage. For simplicity I will post a demo code modelling the issue, with a single string property.
<!-- the main window -->
<Window.DataContext>
<local:CustomerViewModel/>
</Window.DataContext>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" Grid.Row="0">
<Label Content="content of the textbox: " Margin="10"/>
<TextBox Width="300" Text="{Binding Customer.Name}"/>
<Button Content="Update" Command="{Binding UpdateCommand}"/>
</StackPanel>
<DockPanel Grid.Row="1">
<local:TestControl />
</DockPanel>
user control:
<!-- the user control named TestControl-->
<UserControl.DataContext>
<local:CustomerViewModel />
</UserControl.DataContext>
<DockPanel LastChildFill="True">
<Label DockPanel.Dock="Top" Content="Saved" />
<Label DockPanel.Dock="Bottom" Content="{Binding Info, UpdateSourceTrigger=PropertyChanged}" />
</DockPanel>
datamodel class:
public class Customer : ObservableObject
{
private string mName;
public string Name
{
get => mName;
set
{
if (value != mName)
{
mName = value;
OnPropertyChanged(nameof(Name));
}
}
}
}
viewmodel class:
public class CustomerViewModel : ObservableObject
{
private Customer mCustomer;
public Customer Customer
{
get => mCustomer;
set
{
if (value != mCustomer)
{
mCustomer = value;
OnPropertyChanged(nameof(Customer));
}
}
}
private string mInfo;
public string Info
{
get => mInfo;
set
{
if (value != mInfo)
{
mInfo = value;
OnPropertyChanged(nameof(Info));
}
}
}
private ICommand mUpdateCommand;
public ICommand UpdateCommand
{
get
{
if (mUpdateCommand == null)
{
mUpdateCommand = new RelayCommand(p => SaveChanges());
}
return mUpdateCommand;
}
}
public void SaveChanges()
{
Info = Customer.Name + " was updated";
MessageBox.Show(Info);
}
public CustomerViewModel()
{
mCustomer = new Customer();
mCustomer.Name = "Test";
Info = mCustomer.Name;
}
}
The correct value is displayed in the messagebox, but it does not change in the user control. I am calling the property changed interface, and have tried to invoke the button press with dispatcher.invoke, same issue, am I missing something very obvious here?
Your usercontrol is creating its own personal instance of the viewmodel, and using that for its DataContext. That usercontrol instance then sets Info on itself, not on the CustomerViewModel that the parent window has for its own datacontext.
<UserControl.DataContext>
<local:CustomerViewModel />
</UserControl.DataContext>
Remove those three lines from your usercontrol. Keep the corresponding lines in the window. The usercontrol will then inherit its datacontext from its parent, and they'll both be on the same page.
Those three lines aren't just declaring the type of viewmodel the view uses; they're creating an actual instance of the class and assigning it to DataContext.
I have a MVVM WPF project where I have an devexpress accordian control which is populated with xml template items from a ViewModel. That works great, but my problem is when I click on one of the items in the accordian control and the selectedIndexChanged event is fired. I want to handle that in the MVVM manner and get the selected items value(which is a path to an xml file) from the accordian control, fetch the content of the xml file and databind a textbox control with the content of the xml file. The following is what I have tried so far.
Here is my xaml user control
<dxa:AccordionControl Grid.Column="0" x:Name="accordianTemplateMenu"
SelectionMode="Single" SelectionUnit="SubItemOrRootItem" ItemsSource="
{Binding TemplateItems}"
ChildrenPath="TemplateItems" DisplayMemberPath="Header >
<dxmvvm:Interaction.Behaviors>
<dxmvvm:EventToCommand EventName="SelectedItemChanged" Command="
{Binding EditCommand}">
<dxmvvm:EventToCommand.EventArgsConverter>
<Common:AccordionEventArgsConverter/>
</dxmvvm:EventToCommand.EventArgsConverter>
</dxmvvm:EventToCommand>
</dxmvvm:Interaction.Behaviors>
</dxa:AccordionControl>
<GridSplitter Grid.Column="1" />
<TextBlock Grid.Column="2" x:Name="templateItemContainer">
<Run Name="run" Text="{Binding XML}" ></Run>
</TextBlock>
This boils down to the AccordionEventArgsConverter which gets me the event arguments from the selecteditem in the accordian control:
public class AccordionEventArgsConverter :
EventArgsConverterBase<AccordionSelectedItemChangedEventArgs>
{
protected override object Convert(object sender,
AccordionSelectedItemChangedEventArgs args)
{
if (args != null)
{
return args;
}
return null;
}
}
And finally my viewmodel:
class TemplateMenuViewModel
{
private List<TemplateItem> _templateItems;
public TemplateMenuViewModel()
{
EditCommand = new DelegateCommand<object>(Edit, CanEdit);
}
public List<TemplateItem> TemplateItems
{
get
{
TemplateProvider provider = new TemplateProvider();
return provider.GetTemplateMenuItems("pathToMenuItems");
}
set { _templateItems = value; }
}
public ICommand<object> EditCommand { get; private set; }
public void Edit(object accordianItemArgs)
{
}
public bool CanEdit(object accordianItemArgs)
{
return accordianItemArgs != null;
}
}
I am able to get into the public void Edit method, which is great because from there I can use the accordianItemArgs to get the xml content, but how do I "return"/databind the xml content to the textblock element in the xaml file?
There are a couple of things:
You need the TemplateMenuViewModel to define an XML property. It looks like your TextBlock is already binding to it.
Then you need your ViewModel to implement the INotifyPropertyChanged interface. It doesn't look like you're doing that, then raise a property changed event when the XML text is set.
You should set your Text="{Binding XML}" with a Mode of OneWay:
Text="{Binding XML, Mode=OneWay}"
If you need more information on how to implement INotifyPropertyChanged, check out this tutorial: https://www.tutorialspoint.com/mvvm/mvvm_first_application.htm.
In WPF you can modify controls using Styles and Templates dynamically with Binding. I see how to do this in UWP directly in the control but I want to apply a template that will change itself based on the binding.
An example would be a button. I have a button that turns on and off a light in this project. The project is already created and running in WPF but needs to be converted to UWP. In the WPF version we have a LightStyle for the button, depending on what type of light it is, we change the Template to look and perform for that light. (For example: we can change the color of some lights, the dimness for some lights, and some lights just turn on and off; but we use the same LightStyle for them all. Very generic, dynamic, and extremely useful.)
How do you do this in UWP? I've searched a minute and figured I would stop here and check while I continue to dig. Keep in mind that this project is pure MVVM and no code behind is used. I don't mind a code behind explanation as long as it's not the only way.
Thanks in advance :)
Here is a sample I've made - XAML:
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Orientation="Horizontal">
<StackPanel.Resources>
<local:MySelector x:Key="MySelector">
<local:MySelector.GreenTemplate>
<DataTemplate>
<TextBlock Text="{Binding Text}" Foreground="Green"/>
</DataTemplate>
</local:MySelector.GreenTemplate>
<local:MySelector.RedTemplate>
<DataTemplate>
<TextBlock Text="{Binding Text}" Foreground="Red"/>
</DataTemplate>
</local:MySelector.RedTemplate>
</local:MySelector>
</StackPanel.Resources>
<ListView x:Name="ListOfItems" Width="100" ItemTemplateSelector="{StaticResource MySelector}"/>
<StackPanel>
<ToggleSwitch OnContent="GREEN" OffContent="RED" Margin="10" IsOn="{x:Bind IsSwitched, Mode=TwoWay}"/>
<Button Content="Add item" Click="AddClick" Margin="10"/>
</StackPanel>
</StackPanel>
and the code behind:
public sealed partial class MainPage : Page, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void RaiseProperty(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
private bool isSwitched = false;
public bool IsSwitched
{
get { return isSwitched; }
set { isSwitched = value; RaiseProperty(nameof(IsSwitched)); }
}
public MainPage() { this.InitializeComponent(); }
private void AddClick(object sender, RoutedEventArgs e)
{
ListOfItems.Items.Add(new ItemClass { Type = isSwitched ? ItemType.Greed : ItemType.Red, Text = "NEW ITEM" });
}
}
public enum ItemType { Red, Greed };
public class ItemClass
{
public ItemType Type { get; set; }
public string Text { get; set; }
}
public class MySelector : DataTemplateSelector
{
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
switch ((item as ItemClass).Type)
{
case ItemType.Greed:
return GreenTemplate;
case ItemType.Red:
default:
return RedTemplate;
}
}
public DataTemplate GreenTemplate { get; set; }
public DataTemplate RedTemplate { get; set; }
}
Generally you can choose various switches for your selector, it depends on your needs. In above example I'm switching the template basing on the item's property, here is a good example how to switch on item's type.
Here's the answer that I am using that works for my given situation. Basically you have to use a VisualStateTrigger and create the trigger manually via code. There are various triggers you can use and many built in but for this situation I had to, or at least I think I had to, write one manually.
Here's the trigger code.
public class StringComparisonTrigger : StateTriggerBase
{
private const string NotEqual = "NotEqual";
private const string Equal = "Equal";
public string DataValue
{
get { return (string)GetValue(DataValueProperty); }
set { SetValue(DataValueProperty, value); }
}
public static readonly DependencyProperty DataValueProperty =
DependencyProperty.Register(nameof(DataValue), typeof(string), typeof(StringComparisonTrigger), new PropertyMetadata(Equal, (s, e) =>
{
var stringComparisonTrigger = s as StringComparisonTrigger;
TriggerStateCheck(stringComparisonTrigger, stringComparisonTrigger.TriggerValue, (string)e.NewValue);
}));
public string TriggerValue
{
get { return (string)GetValue(TriggerValueProperty); }
set { SetValue(TriggerValueProperty, value); }
}
public static readonly DependencyProperty TriggerValueProperty =
DependencyProperty.Register(nameof(TriggerValue), typeof(string), typeof(StringComparisonTrigger), new PropertyMetadata(NotEqual, (s, e) =>
{
var stringComparisonTrigger = s as StringComparisonTrigger;
TriggerStateCheck(stringComparisonTrigger, stringComparisonTrigger.DataValue, (string)e.NewValue);
}));
private static void TriggerStateCheck(StringComparisonTrigger elementTypeTrigger, string dataValue, string triggerValue)
=> elementTypeTrigger.SetActive(dataValue == triggerValue);
}
This, since inheriting from StateTriggerBase can be used in the VisualStateTriggers group as I will post below. What I didn't know is that any dependency property you write can be used in the XAML and there's no interfaces or anything in the trigger to make it work. The only line of code that fires the trigger is 'SetActive(bool value)' that you must call whenever you want the state to change. By making dependency properties and binding in the XAML you can fire the SetActive whenever the property is changed and therefore modify the visual state.
The DataTemplate is below.
<DataTemplate x:Key="LightsButtonTemplate">
<UserControl>
<StackPanel Name="panel">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<DataTriggers:StringComparisonTrigger DataValue="{Binding Type}"
TriggerValue="READ" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="panel.(UIElement.Background)"
Value="Red" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<TextBlock Text="{Binding Type}" />
<TextBlock Text="{Binding LightStateViewModel.On}" />
</StackPanel>
</UserControl>
</DataTemplate>
And finally using you can use the DataTemplate anywhere but I am using it in an ItemsControl that is bound to a list of LightViewModels.
<ScrollViewer Grid.Row="1">
<ItemsControl ItemsSource="{Binding LightViewModels}"
ItemTemplate="{StaticResource LightsButtonTemplate}" />
</ScrollViewer>
Obviously this isn't the template design I want for the light buttons but this is all I've done to understand and now implement dynamic templates. Hopefully this helps someone else coming from WPF.
The custom trigger class deriving from StateTriggerBase can do and bind anyway you want it to and all you need to do is call SetActive(true) or SetActive(false) whenever you wish to update that trigger. When it's true the VisualState using that trigger will be active.
So I'm brand new to WPF data binding, and it is.. complicated. At this point, I'm trying to just create a list of premade test items and have it displayed in a listbox with a data template when I press a button. After hours of puzzling through tutorials and MSDN this is the best I could come up with.
The data item I want to make a list from:
class ListingItem
{
private string title;
private string user;
private string category;
//Dummy constructor for test purposes
public ListingItem()
{
title = "TestTitle";
user = "TestUser";
category = "TestCatagory";
}
}
The quick and dirty list creator:
class ListMaker
{
public static List<ListingItem> getListing()
{
List<ListingItem> listing = new List<ListingItem>();
for(int i = 0; i <100; i++)
{
listing.Add(new ListingItem());
}
return listing;
}
}
The XAML of the list itself:
<ListBox x:Name="Listing">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Foreground="Gray" Margin="25,0,0,0" Text="{Binding user}"/>
<TextBlock Foreground="Gray" Margin="25,0,0,0" Text="{Binding category}"/>
</StackPanel>
<TextBlock Foreground="Black" Width="270" TextWrapping="Wrap" Text="{Binding title}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
And finally, the button click event which is SUPPOSED to make the magic happen:
private void TabClickEvent(object sender, RoutedEventArgs e)
{
Listing.DataContext = RedditScanner.getListing();
}
Problem is, obviously, the magic is not happening. No errors or anything so easy, I just press that button and dont see any change to the list box. Any help with this?
You cannot bind to private fields. Not even to public fields I think.
Use properties:
class ListingItem
{
//private string title;
//private string user;
//private string category;
public string Title { get; set; }
public string User { get; set; }
public string Category { get; set; }
//Dummy constructor for test purposes
public ListingItem()
{
Title = "TestTitle";
User = "TestUser";
Category = "TestCatagory";
}
}
And for full databinding you would have to implement INotifyPropertyChanged on ListingItem.
the magic is not happening. No errors or anything so easy,
Keep an eye on the Output Window during execution. Binding errors are reported.
Made some minor changes to your code as explained below.
class ListingItem
{
public string title { get; set; }
public string user { get; set; }
public string category { get; set; }
//Dummy constructor for test purposes
public ListingItem()
{
title = "TestTitle";
user = "TestUser";
category = "TestCatagory";
}
}
The list item class, I changed the title, user and category to properties (get;set;). I also needed to make them public so they could be accessed through the binding.
class ListMaker
{
public static List getListing()
{
List listing = new List();
for (int i = 0; i < 100; i++)
{
listing.Add(new ListingItem());
}
return listing;
}
}
No changes to your ListMaker class
public class CommandHandler : ICommand
{
private Action _action;
private bool _canExecute;
public CommandHandler(Action action, bool canExecute=true)
{
_action = action;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_action();
}
}
I introduced a new class to be able to bind the button. This kind of class if relatively common
<Window x:Class="SimpleDatabinding.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:viewmodel="clr-namespace:SimpleDatabinding" Title="MainWindow" Height="350" Width="525"> <Window.DataContext> <viewmodel:MainWindowViewModel/> </Window.DataContext> <Grid> <DockPanel> <Button Command="{Binding FillListCommand}" DockPanel.Dock="Top">Fill List</Button> <ListBox ItemsSource="{Binding Listing}" DockPanel.Dock="Top"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Vertical"> <StackPanel Orientation="Horizontal"> <TextBlock Foreground="Gray" Margin="25,0,0,0" Text="{Binding user}"/> <TextBlock Foreground="Gray" Margin="25,0,0,0" Text="{Binding category}"/> </StackPanel> <TextBlock Foreground="Black" Width="270" TextWrapping="Wrap" Text="{Binding title}"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </DockPanel> </Grid></Window>
Note the addition of xmlns:viewmodel="clr-namespace:SimpleDatabinding". SimpleDatabinding was the name of the project. It's used to locate the view model in the datacontext below.
The Window.DataContext binds the WPF page to the view model. I called my class MainWindowViewModel (see below). This will automatically create an instance of the view model and bind it to the window.
I introduced a button to click. It's bound to a command FillListCommand. I'll define that in the view model below.
I updated the ItemsSource on the ListBox to be bound to the Listing property.
Other than that, I think it's the same.
class MainWindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public List Listing { get; set; }
public CommandHandler FillListCommand { get; set; }
public MainWindowViewModel()
{
FillListCommand = new CommandHandler(DoFillList);
}
public void DoFillList()
{
Listing = ListMaker.getListing();
ProperyHasChanged("Listing");
}
private void ProperyHasChanged(string propertyName)
{
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Finally in the viewmodel class, I implemented the INotifyPropertyChanged interface. This is the mechanism to notify the UI that a value on your view model has changed. In most implementations, this is wrapped in some sort of ViewModel base class but I left it in so you could see it.
As above, I converted the Listing variable to a public property (get;set;) so it could be accessed through the binding.
I created a CommandHandler property called FillListCommand. This uses the class above. The button is bound to this variable. The constructor of the view model initializes and points it to the function to be called when the button is clicked.
Finally, in the DoFillList function, I initialize Listing as you had it but I also use the notification to let the UI know it's changed.
Sorry about all the writing. Hope this is somewhat helpful. I don't think it's too different from what you had.
Don't forget to decorate your data members and service methods with the appropriate tags.
These short videos are great for learning WCF:
http://channel9.msdn.com/Shows/Endpoint?sort=rating#tab_sortBy_rating
There were only 2 problems with my code, which I found:
The properties were set as private in ListingItem, which Henk
Holterman caught (+1ed)
I wasn't setting ItemSource on the list anywhere.
I didn't need to do any of the other stuff Peter Trenery mentioned at all.
I made a custom Class named MedinetParse that parses a webrequest. The parsed data should be showen in a listbox named mittSchemaListBox in the my MainPage. The problem that i'm facing now is that IF i write the parsing method in a custom class named MedinetParse the listbox showes nothing. Althought when i put a breakpoint at the very last line of code inside the parse method, i can see that mittSchemaListBox.ItemsSource have all the parsed items. Meanwhile if i move the parsing method into my MainPage.xaml.cs, then i will see all the parsed item in my listbox.
Here is my MedinetParsing class
namespace WindowsPhonePanoramaApplication1
{
public class MedinetParsing : MainPage
{
//Defining class properties
public string Placering { get; set; }
public string Datum { get; set; }
//Defining class methods
public void parseResults(string myresponse)
{
if (string.IsNullOrEmpty(myresponse))
{
return;
}
//Initiating a listbox and add item to it
List<ItemViewModel> mittSchemaList = new List<ItemViewModel>();
//Using HtmlAgilityPack to parse the HTMLcode from the response
HtmlDocument htdoc = new HtmlDocument();
htdoc.LoadHtml(myresponse);
foreach (HtmlNode table in htdoc.DocumentNode.SelectNodes("//table[#class='list-medium']/tbody[1]/tr[#class]"))
{
//Removing ChildNode
table.ChildNodes.RemoveAt(3);
string itemValue = table.InnerText;
//Changing the parsed date into a DateTime
string d;
DateTime datum = DateTime.Parse(itemValue.Remove(11));
d = datum.ToString("D");
//Adding items to the listbox
mittSchemaList.Add(new ItemViewModel() { Datum = d, Placering = itemValue.Remove(0, 15) });
}
mittSchemaListBox.ItemsSource = mittSchemaList;
}
}
}
Here is the code that initiate the parse:-
public void MainPage_Loaded(object sender, RoutedEventArgs e)
{
if (!App.ViewModel.IsDataLoaded)
{
App.ViewModel.LoadData();
}
MedinetWebRequest mittschema = new MedinetWebRequest();
MedinetParsing mittparse = new MedinetParsing();
mittschema.url = "https://medinet.se/cgi-bin/doctor.pl?action=login&customer=******&language=se";
Action callback = () => Dispatcher.BeginInvoke(() => mittparse.parseResults(mittschema.myresponse));
mittschema.getrequest(callback);
}
And lastly this is my Listbox:-
<ListBox Margin="0,0,-12,0" Name="mittSchemaListBox" DataContext="{Binding}" ItemsSource="{Binding Path=Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,0,0,17">
<!--Replace rectangle with image-->
<Canvas Height="100" Width="100" Margin="12,0,9,0" Background="#FFE5001B">
<TextBlock Text="{Binding Datum}" TextWrapping="Wrap" Height="100" Margin="0" HorizontalAlignment="Right" Width="100" />
</Canvas>
<StackPanel Width="311">
<TextBlock Text="{Binding Placering}" TextWrapping="Wrap" Margin="0,10" Style="{StaticResource PhoneTextExtraLargeStyle}" FontSize="36" TextAlignment="Center" FontWeight="Normal" />
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Been trying to fix this issue for the last few hours and not getting anywhere, i decided to ask here. Hope someone can tell me what is the problem.
Ok, according to your comments, you are doing it the the wrong way. Try this one:
You don't need the new MedinetParing class, just move methods directly to the MainPage code-behind
Update MainPage_Loaded method as follows:
(or consider to move this code to ViewModel as you are using it somehow here)
public void MainPage_Loaded(object sender, RoutedEventArgs e)
{
if (!App.ViewModel.IsDataLoaded)
{
App.ViewModel.LoadData();
}
MedinetWebRequest mittschema = new MedinetWebRequest();
mittschema.url = "https://medinet.se/cgi-bin/doctor.pl?action=login&customer=******&language=se";
Action callback = () => Dispatcher.BeginInvoke(() => this.parseResults(mittschema.myresponse));
mittschema.getrequest(callback);
}
EDIT
public class MedinetParsing // : MainPage -- we don't need this inheritance
{
private readonly MainPage _mainPage;
public MadinetParsing(MainPage mainPage)
{
_mainPage = mainPage;
}
// your code here
// use the next line instead of commented one
// mittSchemaListBox.ItemsSource = mittSchemaList;
_mainPage.mittSchemaListBox.ItemsSource = mittSchemaList;
}
But, as I'm said before, the best solution will be to do parse in the ViewModel and use binding to populate the ListBox.
Could not answer my question last night so here is the answer.
Again after few hours getting back and forth with my code i just found out a solution that fits my app. The solution is that i changed this line of code in my MedinetParsing class
mittSchemaList.Add(new ItemViewModel() { Datum = d, Placering = itemValue.Remove(0, 15) });
with this one:-
App.ViewModel.Items.Add(new ItemViewModel() {Datum=d,Placering=itemValue.Remove(0,15)});
Got rid of this line of code:-
mittSchemaListBox.ItemsSource = mittSchemaList;
Now it is working like it should and i'm happy ;).
Hope this will help someothers if they face such a problem.
Yours