Mvvm - Updating Binding takes too long - performance

I have a 5 ViewModels. Every view has their own VM. When I start the program, the ViewModel changes the bindings, i.e.
private string _bruttolohn;
public string Bruttolohn
{
get { return _bruttolohn; }
set
{
if (value != null)
{
if (value != _bruttolohn)
{
_bruttolohn = value;
Calculate();
RaisePropertyChanged(() => Bruttolohn);
}
}
}
}
Bruttolohn = some value I put in to calculate and set the new values. I have ~100 other propertys, which are all using Binding. If I start the program, the calculation is fine and works fast! But when I change the View (All views are in a ContentControl. If I click on a button, the view is being changed like this: MyContent.Content = new FirstView();). Now here's the problem: If I change the view ~30 times, the ViewModel needs way too long to set the bindings. Why!?
+ If I debug and I'm at this point:
RaisePropertyChanged(() => Bruttolohn);
Error pops up: ObservableObject.cs is missing...?

There is nothing wrong with the code you've shown so I suspect the Calculation method. Profile it.
If the Calculation() method is too long to post, it shouldn't be in a property setter :)

I guess I found the solution. Every time I click on the button "FirstView", the Content of the ContentControl gets a NEW VIEW()! So every time I click on the button, it'll do:
MyContent.Content = new FirstView();
This means that there are still somehow Views in the background open... I can't explain it by myself, but if I set the View globally like
FirstView fw;
and say in the constructor of the MainViewModel
fw = new FirstView();
I can easily assign the content of my ContentControl like this (without creating a new View):
MyContent.Content = fw;
You can download a test app here: http://www65.zippyshare.com/v/89159114/file.html
It has a MainView and 2 Views. It shows my problem. If you click on the Button "FirstView", the content of the contentcontrol will be "FirstView.xaml". It has 2 textboxes, which calculate the sum and has a for-loop (for i = 0, i < 500, i++). If you calculate right at the start, the calculation takes only ~1 sec, but if you click the Button "FirstView" ~30 times and try to calculate again, the calculation takes more than 10 sec!!!
I thinks it's because of MyContent.Content = new FirstView(); You can check my program and correct me if I'm wrong or say if I'm right... Like I said, I think that this is the solution, but I'm not 100% sure.

if Calculate() isn't an async method, it blocks the UI.
You could use
Task.Run(() =>
{
Calculate();
RaisePropertyChanged(() => Bruttolohn);
});
Not relevant to your question, but maybe interesting:
if (value != _bruttolohn)
Strings should be compared using .Equals, as the same string can be referenced to different places in the heap.
So:
if (value == null || !value.Equals(_bruttolohn))

Related

How to show and hide standard InDesign panels through scripting?

I’m able to get a reference to, for instance, the “Scripts” panel; but it doesn’t seem to have the show and hide methods like panels created through scripting (see code below). How can I get it to show or hide programmatically, without invoking the corresponding menu item?
function findPanelByName(name) { // String → Panel|null
for (var iPanel = 0; iPanel < app.panels.length; iPanel++) {
var panel = app.panels[iPanel];
if (panel.name == name) {
return panel;
}
}
return null;
}
var scriptsPanel = findPanelByName('Scripts');
scriptsPanel.show(); // → “scriptsPanel.show is not a function”
A few things: Your method to get the right panel is unneccessarily complicated. You could just get the panel by using the panel collection's item method like so:
var scriptsPanel = app.panels.item('Scripts');
Then, you don't need to use show() to show the panel (as that method does not exist), but you can just show the panel, by settings its visible property to true:
scriptsPanel.visible = true;
And lastly, in case anybody else is supposed to use the script, you should make sure, that it works with international versions of InDesign as well. In my German version, the above panel for example would not exist, as it is named Skripte instead of Scripts. To avoid that you can use the language independent key of InDesign:
var scriptsPanel = app.panels.item('$ID/Scripting');
So, in conclusion, the entire script could be shortened up to this one-liner
app.panels.item('$ID/Scripting').visible = true;

passing control indexer by reference to method to change its property

i have made a program, which include a lot of controls. The controls would be showed and hided according to the choice of the user. That means that controls overlapped on each other at design time. now i want to change the forecolor and backcolor of all controls at design time. but i founded so hard to accomplish this task, because all the control overlapping each other. so I decided to make a for loop method to iterate the controls in the form and then check each control in turn whether it has controls. when the control has also controls in it, I call the same method and pass the control to it to change the properties for the subcontrols too. The method like so:
void setColor(ref Control con)
{
con.BackColor= System.Drawing.Color.Black;
con.ForeColor=System.Drawing.Color.Yellow;
if (con.Controls.Count > 0) { setColor(ref con); }
}
so my Form include tabControl with multiple tabPages. I iterate the tabPages and wanted to pass it to this method, but I become error "Indexer may not be passed as an out or ref parameter"
I pass it so: setColor(ref tabControl1.Controls[i]);
can you please help me to solve this problem?
I have resolved the problem.
I have removed the "ref" from method and wrote the method simply like the following:
void SetColor(Control con)
{
con.BackColor = System.Drawing.Color.Black;
con.ForeColor = System.Drawing.Color.Yellow;
if (con.Controls.Count > 0)
{
for (int i=0; i<con.Controls.Count;i++)
SetColor(con.Controls[i]);
}
}
and call it so: setColor(this.Controls[i]);

RadioButton isChecked control state android

Here is the case : i have 4 radioButtons that are not members of a radioGroup. Thats because RadioGroup places children in vertical order by default and cannot place them relative to each other.Right now , i am check all the radioButtons. What i want to achieve is to control their checked state , so that when one is checked(true) the others checked state is set automatically to false. There widgets are independent layout elements , so i guess i have to find a way to group them all together. I tried it by coding 4 RadioButton variables with a simple if..else if function using isChecked and setChecked built-in methods. Then i tried grouping them in an Radiobutton[] array and looping to the array.length with a switch-case loop. Nothing works.
Stack for 2 days now. Any help appreciated.
Thanks for reply , i explain further. I have 4 imageViews and 4 radioButtons exactly below each one , in a RelativeLayout parent , so that the user can make a choise which image he prefers. The imageViews are not vertically placed , so are the radioButtons. Thats why i dont want to use radioGroup. I could use LinearLayout and place imageViews in vertical orientation and have the radioButtons in a group just aside them. Every radioButton checked state is false by default and when i check it , becomes true. The problem is that i can check all of the radioButtons . What i want is when i select one RadioButton , the others are automatically unchecked , so that only one may be checked at any time.
Here is the snippet:
private RadioButton rbtnWater;
private RadioButton rbtnRoad;
private RadioButton rbtnBoy;
private RadioButton rbtnLeft;
rbtnWater = (RadioButton) findViewById(R.id.rbtnWater);
rbtnRoad = (RadioButton) findViewById(R.id.rbtnRoad);
rbtnBoy = (RadioButton)findViewById(R.id.rbtnBoy);
rbtnLeft = (RadioButton) findViewById(R.id.rbtnLeft)
//method called at onClick attribute (XML)
public void checkState(View v) {
if (rbtnWater.isChecked()) {
rbtnLeft.setChecked(false);
rbtnBoy.setChecked(false);
rbtnRoad.setChecked(false);
}
else if (rbtnLeft.isChecked()) {
rbtnBoy.setChecked(false);
rbtnWater.setChecked(false);
rbtnRoad.setChecked(false);
}
else if (rbtnBoy.isChecked()) {
rbtnWater.setChecked(false);
rbtnRoad.setChecked(false);
rbtnLeft.setChecked(false);
}
else if (rbtnRoad.isChecked()) {
rbtnWater.setChecked(false);
rbtnBoy.setChecked(false);
rbtnLeft.setChecked(false);
}
}
It not really clear what is not working, please add details
That being said I suggest you change the technique and use a RadioGroup anyway, just extend it and modify to what you need or take it's source code from AOSP and instead of having it extend a LinearLayout you can extend something else you would rather work with

Animate Button size, then revert to null

I am trying to create an animation to make it look like a button turns over and the back shows. So what I was trying to do is:
1- Show a button with BackgroundColor x. (The button now has a Width of null, the property ActualWidth does have a value.)
2- Create a double animation that changes the width of the button to zero.
DoubleAnimation widthAnimation = new DoubleAnimation();
widthAnimation.From = this.ActualWidth;
widthAnimation.To = 0;
widthAnimation.SpeedRatio = 3;
widthAnimation.Duration = TimeSpan.FromMilliseconds(800);
3- Change the BackgroundColor of the button.
ColorAnimation colorAnimation = new ColorAnimation();
colorAnimation.From = State ? _xColor : _yColor;
colorAnimation.To = State ? _yColor : _xColor;
colorAnimation.BeginTime = TimeSpan.FromMilliseconds(400);
colorAnimation.Duration = TimeSpan.Zero;
4- Change the width back to it's original value.
widthAnimation.AutoReverse = true;
The problem is when the animation runs twice the animation reads this.ActualWidth while animating, which causes it to fail to the original width. How can I solve this? I would like to set the Width back to null again, but it seems impossible to me.
You'd better use xaml style and template to "declare" what you want and let WPF/Silverlight take care of all.
If you try to do the same thing by code you can do it but you need to know what the framework does behind the scenes.
Basically you can set
- Style to define the values of some properties of the control
- DataTemplate to define the visual representation of the control's content
- ControlTemplate to define the appearance of the control
Each of those can have Triggers
- Property Triggers
to set properties or starts actions, such as an animation
when a property value changes or when an event is raised;
EventTriggers and Storyboards
to start a set of actions based on the occurrence of an event
If you like to learn about XAML Style and Template,
take a look at http://msdn.microsoft.com/en-us/library/ms745683.aspx
Spend a day to learn and save many hours (or days) of try and error and frustration!
To go right to the point, in your case I think you should use a Storyboard.
See http://msdn.microsoft.com/en-us/library/ms742868.aspx
where you can find also the code equivalent of XAML examples
I came to the idea to targetting the MaxWidth instead of the actual Width. I now use a KeyFrameCollection which sets the MaxWidth to int.MaxValue at the start (so also at the end when using autoreverse).
It will work fine untill there will be phones with a resolution bigger than the max int value.
The code:
DoubleAnimationUsingKeyFrames widthAnimation = new DoubleAnimationUsingKeyFrames();
widthAnimation.KeyFrames.Add(new DiscreteDoubleKeyFrame()
{
KeyTime = TimeSpan.Zero,
Value = int.MaxValue,
});
widthAnimation.KeyFrames.Add(new LinearDoubleKeyFrame()
{
KeyTime = TimeSpan.FromMilliseconds(1),
Value = ActualWidth,
});
widthAnimation.KeyFrames.Add(new LinearDoubleKeyFrame()
{
KeyTime = TimeSpan.FromMilliseconds(400),
Value = 0,
});
widthAnimation.Duration = TimeSpan.FromMilliseconds(400);
widthAnimation.AutoReverse = true;

Restore Scroll Position in LongListSelector after tombstone

I'm trying to work with the LongListSelector control from the WP7 Silverlight Toolkit. It's taken a bit of work, but I finally have it working with my app. Unfortunately, I am having some trouble properly handling the tombstoning process.
When the application tombstones (or the user navigates to another page by selecting an item in the list), I save a copy of the topmost visible item in the list. I save it to both a class variable and to the app state collection.
ICollection<object> visibleItems = myLongList.GetItemsInView();
_lastItem = null;
if (visibleItems.Count > 0)
_lastItem = visibleItems.First();
IDictionary<string, object> state =
Microsoft.Phone.Shell.PhoneApplicationService.Current.State;
state["IndexByName_LastTopItem"] = _lastItem;
Then, when the user returns to the page I check for one of the two values (state or variable) and use it to restore the last scroll position.
if (_lastItem == null)
{
if (state.ContainsKey("IndexByName_LastTopItem"))
{
_lastItem = state["IndexByName_LastTopItem"] as Chemical;
}
}
if (_lastItem != null)
Dispatcher.BeginInvoke(() => { myLongList.ScrollTo(_lastItem); });
This works great unless the application tombstones. In that case I don't get any errors, but the list is completely blank until I touch it and drag. Once I do that, it redisplays at the top of the list. I took a look at the source for the control and found that when you call .ScrollTo(object) it doesn't get a match. Further investigation identified that when searching for an item to scroll to, it compares using == instead of Equals. I only overrode Equals, and apparently the default == compares (by design) references. When you restore a State item after tombstoning the references don't match.
I can override ==, but that feels wrong. I can change and rebuild the control source to call equals instead (I tried and it worked), but it was written by people much smarter than I and I'm wondering if I just don't get it.
Is there a better way?
This is the fix I ended up coming up with...
Since the source code is freely available for the Toolkit, I ended up editing the LongListSelector source code to call .Equals instead of ==. It seems to work properly for my use case and I thought I'd share in case anyone else finds it useful...
in LongListSelector.cs find the GetFlattenedIndex(object item) function and replace
if (item == _flattenedItems[index].Item)
with
if (item.Equals(_flattenedItems[index].Item))
and then in the same file find the GetResolvedIndex(object item, out ContentPresenter contentPresenter) function and replace
if (node.Value.Content == item) // Nov 2010 Release
// OR
if (_flattenedItems[index].Item == item) // Feb 2011 Release
with
if (item.Equals(node.Value.Content)) // Nov 2010 Release
// OR
if (item.Equals(_flattenedItems[index].Item)) // Feb 2011 Release
NOTE that the replace depends on which toolkit download you are using!
Once you have made these changes to the control, it will properly match up objects specified in ScrollTo(object), even if the references are not equal as long as you properly override Equals for all object types displayed in your LongListSelector. Don't forget this applies to your Grouping class as well as your item class if you have a grouped list!
Can you try to get the item in the new list ?
var _goodReference = myList.FirstOrDefault(x => x.id == _lastItem.Id);
if (_goodReference != null)
Dispatcher.BeginInvoke(() => { myLongList.ScrollTo(_goodReference); });

Resources